klue-langcraft 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '07528e25c004b36664752d235737a9f6f521e231eb2b9e900884861e2fbeccad'
4
- data.tar.gz: bd96ac7b1247f8f4fe123b4bb7923df50f1067120b1faa6e1121c6936fe400d1
3
+ metadata.gz: 991b394224dd15a2eccfe3ce1db7b6bca00304d8c6cf75ac8763a34beb6b9d06
4
+ data.tar.gz: 9a814b4cb28a1eefe7763c7705f652f754c567404748e326c60049e7d9f7f7c1
5
5
  SHA512:
6
- metadata.gz: f270af8583b0ef01f5c290f0d69abe2de5534682169440381532fea9510c0b2b03f7c247c13dcde3fd13dc88b89fdadc3255af804138b6373513ea16a32b31d6
7
- data.tar.gz: e23279553bc9f644ebe56ce796dd99cda278c10170142806e2a9ed59839a3a51a541de9b0b75082474e46f130cd6e3e5d037d2c5e9c475585280ba032d84a6d8
6
+ metadata.gz: e34c11144fefacb28af86e336e48f5bc905fb2a4db2ea75079689fcd21a1ecbc2f5ea8a6ffac8fbc16713a32323007279c3b208655c3864d29861848d84b38d2
7
+ data.tar.gz: 990a9b599923fc5a7117f0fafe0a20057f63798ebbef06a02de8b9debc3b900b6bc1797a9fcd472301b74d10944077077e25aa333fd001a81b88619fdecd668e
data/.rubocop.yml CHANGED
@@ -40,8 +40,23 @@ Metrics/BlockLength:
40
40
  - shared_examples_for
41
41
  - transaction
42
42
 
43
+ Metrics/AbcSize:
44
+ Exclude:
45
+ - bin/*
46
+
47
+
43
48
  Metrics/MethodLength:
44
49
  Max: 25
50
+ Exclude:
51
+ - bin/*
52
+
53
+ Metrics/PerceivedComplexity:
54
+ Exclude:
55
+ - bin/*
56
+
57
+ Metrics/CyclomaticComplexity:
58
+ Exclude:
59
+ - bin/*
45
60
 
46
61
  Layout/LineLength:
47
62
  Max: 200
@@ -55,7 +70,7 @@ Lint/UnusedMethodArgument:
55
70
  Style/BlockComments:
56
71
  Enabled: false
57
72
  Include:
58
- - "**/spec/*"
73
+ - "**/spec/**/*"
59
74
 
60
75
  # My Preferences - Start
61
76
  Metrics/ClassLength:
@@ -75,8 +90,8 @@ Style/EmptyMethod:
75
90
  Exclude:
76
91
  - "**/spec/**/*"
77
92
  Metrics/ParameterLists:
78
- Exclude:
79
- - "**/spec/**/*"
93
+ Enabled: false
94
+
80
95
  Layout/EmptyLineBetweenDefs:
81
96
  Exclude:
82
97
  - "**/spec/**/*"
data/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ # [0.3.0](https://github.com/appydave/klue-langcraft/compare/v0.2.0...v0.3.0) (2024-10-26)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * fix cop ([d77187a](https://github.com/appydave/klue-langcraft/commit/d77187ac59088b7ce6ca23630a06fbb007f05fb4))
7
+
8
+
9
+ ### Features
10
+
11
+ * update cli for watch and process ([9f0eeb1](https://github.com/appydave/klue-langcraft/commit/9f0eeb1a9409f6734d4ab930ca5c3164b71446eb))
12
+
13
+ # [0.2.0](https://github.com/appydave/klue-langcraft/compare/v0.1.1...v0.2.0) (2024-10-25)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * fix ci issue ([a3bfd35](https://github.com/appydave/klue-langcraft/commit/a3bfd35371b7c0ca70b0b57d70d4541c7a4ec54b))
19
+ * fix cop ([123070b](https://github.com/appydave/klue-langcraft/commit/123070bd1f636a81d01da469c2e5072c57384bae))
20
+ * update dsl_interpreter ([2507045](https://github.com/appydave/klue-langcraft/commit/2507045c3f7f205603a3f899785e9c5445c4c0bb))
21
+
22
+
23
+ ### Features
24
+
25
+ * refactor dsl processor ([5875dc9](https://github.com/appydave/klue-langcraft/commit/5875dc957789f113da762a6dcb55cda66bfb8a3d))
26
+
1
27
  ## [0.1.1](https://github.com/appydave/klue-langcraft/compare/v0.1.0...v0.1.1) (2024-09-22)
2
28
 
3
29
 
data/bin/langcraft.rb ADDED
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
5
+
6
+ require 'klue/langcraft'
7
+ require 'optparse'
8
+
9
+ # CLI class for the Klue Langcraft application.
10
+ # This class handles command-line interactions, parsing options,
11
+ # and executing the appropriate commands for processing files
12
+ # or watching directories.
13
+ class CLI
14
+ def initialize
15
+ @commands = {
16
+ 'process' => method(:process_files),
17
+ 'watch' => method(:watch_files)
18
+ }
19
+ end
20
+
21
+ def run
22
+ if ARGV.empty?
23
+ print_help
24
+ exit
25
+ end
26
+
27
+ command, *args = ARGV
28
+ if @commands.key?(command)
29
+ @commands[command].call(args)
30
+ else
31
+ puts "Unknown command: #{command}"
32
+ print_help
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def process_files(args)
39
+ options = {}
40
+ parser = OptionParser.new do |opts|
41
+ opts.banner = 'Usage: langcraft process [options]'
42
+
43
+ opts.on('-i', '--input FILE', 'Input file (required)') do |file|
44
+ options[:input] = file
45
+ end
46
+
47
+ opts.on('-b', '--basic-output FILE', 'Output file') do |file|
48
+ options[:basic_output] = file
49
+ end
50
+
51
+ opts.on('-e', '--enhanced-output FILE', 'Output file') do |file|
52
+ options[:enhanced_output] = file
53
+ end
54
+
55
+ opts.on('-u', '--webhook-url URL', 'Webhook URL') do |url|
56
+ options[:webhook_url] = url
57
+ end
58
+
59
+ opts.on('-d', '--debug LEVEL', %i[none info detailed], 'Debug level (none, info, detailed)') do |level|
60
+ options[:debug] = level
61
+ end
62
+
63
+ opts.on('-h', '--help', 'Show this message') do
64
+ puts opts
65
+ exit
66
+ end
67
+ end
68
+
69
+ parser.parse!(args)
70
+
71
+ if validate_options(options)
72
+ run_klue_runner(options)
73
+ else
74
+ print_usage(parser)
75
+ end
76
+ end
77
+
78
+ def validate_options(options)
79
+ if options[:input].nil?
80
+ puts 'Error: Input file is required.'
81
+ false
82
+ else
83
+ true
84
+ end
85
+ end
86
+
87
+ def run_klue_runner(options)
88
+ klue_runner = Klue::Langcraft::DSL::KlueRunner.new
89
+ klue_runner.run(
90
+ input_file: options[:input],
91
+ basic_output_file: options[:basic_output],
92
+ enhanced_output_file: options[:enhanced_output],
93
+ webhook_url: options[:webhook_url],
94
+ debug: options[:debug] || :none
95
+ )
96
+ rescue StandardError => e
97
+ puts "Error: #{e.message}"
98
+ exit 1
99
+ end
100
+
101
+ def print_usage(parser)
102
+ puts 'Error: Invalid or missing options.'
103
+ puts
104
+ puts parser
105
+ exit 1
106
+ end
107
+
108
+ def watch_files(args)
109
+ options = {
110
+ directories: [],
111
+ create_basic_json: false,
112
+ create_enhanced_json: false,
113
+ log_level: :info,
114
+ webhook_url: nil,
115
+ extensions: ['.klue'] # Default extension
116
+ }
117
+ OptionParser.new do |opts|
118
+ opts.banner = 'Usage: server watch [options]'
119
+
120
+ opts.on('-w', '--watch-directory DIRECTORY', 'Directory to watch (can be specified multiple times)') do |dir|
121
+ options[:directories] << File.expand_path(dir) # Expand the path here
122
+ end
123
+
124
+ opts.on('-f', '--flags TYPE', 'Set processing flags (none, basic, enhanced, all)') do |type|
125
+ types = type.split(',').map(&:strip).map(&:downcase)
126
+ options[:create_basic_json] = types.include?('basic') || types.include?('all')
127
+ options[:create_enhanced_json] = types.include?('enhanced') || types.include?('all')
128
+ end
129
+
130
+ opts.on('-l', '--log-level LEVEL', %i[none info detailed], 'Log level (none, info, detailed)') do |level|
131
+ options[:log_level] = level
132
+ end
133
+
134
+ opts.on('-u', '--webhook-url URL', 'Webhook URL') do |url|
135
+ options[:webhook_url] = url
136
+ end
137
+
138
+ opts.on('-e', '--extensions EXT1,EXT2,...', Array, 'File extensions to watch (default: .klue)') do |exts|
139
+ options[:extensions] = exts.map { |ext| ext.start_with?('.') ? ext : ".#{ext}" }
140
+ end
141
+
142
+ opts.on('-h', '--help', 'Show this message') do
143
+ puts opts
144
+ exit
145
+ end
146
+ end.parse!(args)
147
+
148
+ # If no directories were specified, use the current directory
149
+ options[:directories] = [Dir.pwd] if options[:directories].empty?
150
+
151
+ # Ensure all directories are expanded
152
+ options[:directories].map! { |dir| File.expand_path(dir) }
153
+
154
+ Klue::Langcraft::DSL::Watcher.new(
155
+ options[:directories],
156
+ create_basic_json: options[:create_basic_json],
157
+ create_enhanced_json: options[:create_enhanced_json],
158
+ log_level: options[:log_level],
159
+ webhook_url: options[:webhook_url],
160
+ extensions: options[:extensions]
161
+ ).start
162
+ end
163
+
164
+ def print_help
165
+ puts 'Klue Langcraft Server'
166
+ puts 'Usage: server [command] [options]'
167
+ puts ''
168
+ puts 'Commands:'
169
+ puts ' process Process a single file'
170
+ puts ' watch Watch directories for changes'
171
+ puts ''
172
+ puts "Run 'server [command] --help' for more information on a command."
173
+ end
174
+ end
175
+
176
+ # Run the CLI
177
+ CLI.new.run
@@ -17,18 +17,18 @@ module Klue
17
17
  attr_accessor :processed
18
18
 
19
19
  def initialize
20
- @data = {}
21
- @processed = false
20
+ klue_reset
22
21
  end
23
22
 
24
23
  def process(input: nil, input_file: nil, output_file: nil)
25
- validate_input_arguments(input, input_file)
26
- input_content = input_content(input, input_file)
24
+ klue_reset
25
+ klue_validate_input_arguments(input, input_file)
26
+ klue_input_content = klue_input_content(input, input_file)
27
27
 
28
28
  @processed = true
29
- instance_eval(input_content)
29
+ instance_eval(klue_input_content)
30
30
 
31
- write_output(output_file) if output_file
31
+ klue_write_output(output_file) if output_file
32
32
  data
33
33
  end
34
34
 
@@ -36,7 +36,7 @@ module Klue
36
36
  raise "You must call 'process' before using other methods" unless @processed
37
37
 
38
38
  key = method_name
39
- value = process_args(args, block)
39
+ value = klue_process_args(args, block)
40
40
 
41
41
  if @data[key]
42
42
  @data[key] = [@data[key]] unless @data[key].is_a?(Array)
@@ -50,7 +50,7 @@ module Klue
50
50
  @processed || super
51
51
  end
52
52
 
53
- def process_args(args, block)
53
+ def klue_process_args(args, block)
54
54
  positional_args = []
55
55
  named_args = {}
56
56
 
@@ -82,32 +82,32 @@ module Klue
82
82
 
83
83
  private
84
84
 
85
- def validate_input_arguments(input, input_file)
85
+ def klue_reset
86
+ @data = {}
87
+ @processed = false
88
+ end
89
+
90
+ def klue_validate_input_arguments(input, input_file)
86
91
  raise ArgumentError, 'Either input or input_file must be provided' unless input || input_file
87
92
  raise ArgumentError, 'Both input and input_file cannot be provided' if input && input_file
88
93
  end
89
94
 
90
- def input_content(input, input_file)
95
+ def klue_input_content(input, input_file)
91
96
  input_file ? File.read(input_file) : input
92
97
  end
93
98
 
94
- def write_output(output_file)
95
- output_path = get_output_path(output_file)
99
+ def klue_write_output(output_file)
100
+ output_path = klue_output_path(output_file)
96
101
  File.write(output_path, JSON.pretty_generate(data))
97
102
  end
98
103
 
99
- def get_output_path(output_file)
104
+ def klue_output_path(output_file)
100
105
  if Pathname.new(output_file).absolute?
101
106
  output_file
102
107
  else
103
108
  File.join(File.dirname(output_file), File.basename(output_file))
104
109
  end
105
110
  end
106
-
107
- # Convert to JSON
108
- def to_json(*_args)
109
- @data.to_json
110
- end
111
111
  end
112
112
  end
113
113
  end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Klue
4
+ module Langcraft
5
+ module DSL
6
+ # KlueRunner handles the processing of DSL input data
7
+ # It manages the execution of various processors and the output of processed data
8
+ class KlueRunner
9
+ attr_reader :interpreter, :pipeline, :webhook
10
+
11
+ def initialize
12
+ @interpreter = Klue::Langcraft::DSL::Interpreter.new
13
+ @pipeline = Klue::Langcraft::DSL::ProcessDataPipeline.new(Klue::Langcraft::DSL::ProcessMatcher.new)
14
+ @webhook = Klue::Langcraft::DSL::Webhook.new
15
+ end
16
+
17
+ # Run the KlueRunner with the given input data
18
+ # @param input [String] The input data to process
19
+ # @param input_file [String] The input file to process (input data and file are mutually exclusive)
20
+ # @param basic_output_file [String] The output file to write the processed data, this file is before any processing
21
+ # @param enhanced_output_file [String] The output file to write the processed data, this file is after processing
22
+ def run(
23
+ input: nil,
24
+ input_file: nil,
25
+ basic_output_file: nil,
26
+ enhanced_output_file: nil,
27
+ webhook_url: nil,
28
+ log_level: :none
29
+ )
30
+ @log_level = log_level
31
+
32
+ log_info('Processing input')
33
+ data = interpreter.process(input: input, input_file: input_file, output_file: basic_output_file)
34
+ log_detailed('Interpreter output:', data)
35
+
36
+ log_info('Executing pipeline - enhance')
37
+ enhanced_data = pipeline.execute(data)
38
+ log_detailed('Enhanced output:', enhanced_data)
39
+
40
+ if enhanced_output_file
41
+ log_info("Writing enhanced output to file: #{enhanced_output_file}")
42
+ @pipeline.write_output(enhanced_data, enhanced_output_file)
43
+ end
44
+
45
+ if webhook_url
46
+ log_info("Delivering data to webhook: #{webhook_url}")
47
+ @webhook.deliver(webhook_url, enhanced_data)
48
+ end
49
+
50
+ log_info('Processing complete')
51
+ end
52
+
53
+ private
54
+
55
+ def log_info(message)
56
+ puts message if %i[info detailed].include?(@log_level)
57
+ end
58
+
59
+ def log_detailed(message, data)
60
+ return unless @log_level == :detailed
61
+
62
+ puts message
63
+ pp data
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'listen'
4
+
5
+ module Klue
6
+ module Langcraft
7
+ module DSL
8
+ # Watcher class for monitoring file changes in specified directories.
9
+ # This class sets up a file system listener to watch for changes to files
10
+ # with specified extensions, and processes those files using a KlueRunner.
11
+ class Watcher
12
+ def initialize(directories, **options)
13
+ @directories = directories.map { |dir| File.expand_path(dir) }
14
+ @options = options
15
+ @klue_runner = Klue::Langcraft::DSL::KlueRunner.new
16
+ @extensions = options[:extensions] || ['.klue']
17
+ end
18
+
19
+ def start
20
+ listener = create_listener
21
+ log_watcher_info
22
+ listener.start
23
+ sleep
24
+ end
25
+
26
+ private
27
+
28
+ def create_listener
29
+ extension_regex = create_extension_regex
30
+ Listen.to(*@directories, only: extension_regex) do |modified, added, _removed|
31
+ process_changed_files(modified + added)
32
+ end
33
+ end
34
+
35
+ def create_extension_regex
36
+ Regexp.union(@extensions.map { |ext| /#{Regexp.escape(ext)}$/ })
37
+ end
38
+
39
+ def process_changed_files(files)
40
+ files.each { |file| process_file(file) }
41
+ end
42
+
43
+ def process_file(file)
44
+ log_info('Processing file', file)
45
+ options = create_file_options(file)
46
+ run_klue_runner(options)
47
+ rescue StandardError => e
48
+ log_error('Error processing file', "#{file}: #{e.message}")
49
+ end
50
+
51
+ def create_file_options(file)
52
+ options = @options.dup
53
+ options[:input_file] = file
54
+ options[:basic_output_file] = file.sub(/#{File.extname(file)}$/, '.json') if @options[:create_basic_json]
55
+ options[:enhanced_output_file] = file.sub(/#{File.extname(file)}$/, '.enhanced.json') if @options[:create_enhanced_json]
56
+ options
57
+ end
58
+
59
+ def run_klue_runner(options)
60
+ @klue_runner.run(
61
+ input_file: options[:input_file],
62
+ basic_output_file: options[:basic_output_file],
63
+ enhanced_output_file: options[:enhanced_output_file],
64
+ webhook_url: options[:webhook_url],
65
+ log_level: options[:log_level]
66
+ )
67
+ end
68
+
69
+ def log_watcher_info
70
+ log_info('Watching directories', @directories.join(', '))
71
+ log_info('Watching file extensions', @extensions.join(', '))
72
+ log_info('Create basic JSON', @options[:create_basic_json])
73
+ log_info('Create enhanced JSON', @options[:create_enhanced_json])
74
+ log_info('Webhook URL', @options[:webhook_url])
75
+ log_info('Log level', @options[:log_level])
76
+ end
77
+
78
+ def log_info(label, value)
79
+ puts "#{label.ljust(30)}: #{value}" if %i[info detailed].include?(@options[:log_level])
80
+ end
81
+
82
+ def log_error(label, value)
83
+ puts "#{label.ljust(30)}: #{value}"
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
6
+
7
+ module Klue
8
+ module Langcraft
9
+ module DSL
10
+ # Webhook class for handling HTTP POST requests to specified URLs.
11
+ # This class is responsible for sending processed data to external services
12
+ # via webhooks, handling the delivery process, and logging the results.
13
+ class Webhook
14
+ def deliver(webhook_url, data)
15
+ klue_type = extract_klue_type(data)
16
+ uri = build_uri(webhook_url, klue_type)
17
+ response = send_request(uri, build_payload(klue_type, data))
18
+ log_response(response, uri)
19
+ response
20
+ end
21
+
22
+ private
23
+
24
+ def extract_klue_type(data)
25
+ data.keys.first.to_s
26
+ end
27
+
28
+ def build_uri(webhook_url, klue_type)
29
+ URI.parse("#{webhook_url}?klue-type=#{klue_type}")
30
+ end
31
+
32
+ def build_payload(klue_type, data)
33
+ { klue_type: klue_type, data: data }
34
+ end
35
+
36
+ def send_request(uri, payload)
37
+ http = Net::HTTP.new(uri.host, uri.port)
38
+ request = Net::HTTP::Post.new(uri.path, { 'Content-Type' => 'application/json' })
39
+ request.body = payload.to_json
40
+ http.request(request)
41
+ end
42
+
43
+ def log_response(response, uri)
44
+ puts "Response: #{response.code} - #{response.message}"
45
+ puts "Endpoint: #{uri}"
46
+ log_response_body(response)
47
+ end
48
+
49
+ def log_response_body(response)
50
+ body = JSON.parse(response.body)
51
+ puts "DSL Type: #{body['type']}"
52
+ # puts JSON.pretty_generate(body['data'])
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Klue
4
4
  module Langcraft
5
- VERSION = '0.2.0'
5
+ VERSION = '0.4.0'
6
6
  end
7
7
  end
@@ -19,12 +19,9 @@ require 'klue/langcraft/dsl/processors/full_name_processor'
19
19
  require 'klue/langcraft/dsl/interpreter'
20
20
  require 'klue/langcraft/dsl/process_matcher'
21
21
  require 'klue/langcraft/dsl/process_data_pipeline'
22
-
23
- require 'base_process'
24
- require 'process_file_collector'
25
- require 'dsl_interpreter'
26
- require 'dsl_folder_watcher'
27
- require 'dsl_process_data'
22
+ require 'klue/langcraft/dsl/webhook'
23
+ require 'klue/langcraft/dsl/watcher'
24
+ require 'klue/langcraft/dsl/klue_runner'
28
25
 
29
26
  module Klue
30
27
  module Langcraft
data/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "klue-langcraft",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "klue-langcraft",
9
- "version": "0.2.0",
9
+ "version": "0.4.0",
10
10
  "devDependencies": {
11
11
  "@klueless-js/semantic-release-rubygem": "github:klueless-js/semantic-release-rubygem",
12
12
  "@semantic-release/changelog": "^6.0.3",
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klue-langcraft",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Domain Specific Language Crafting",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klue-langcraft
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-25 00:00:00.000000000 Z
11
+ date: 2024-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appydave-tools
@@ -61,7 +61,7 @@ files:
61
61
  - README.md
62
62
  - Rakefile
63
63
  - bin/console
64
- - bin/dsl_watcher.rb
64
+ - bin/langcraft.rb
65
65
  - bin/setup
66
66
  - docs/dsl-class-diagram.md
67
67
  - docs/dsl-examples.md
@@ -78,24 +78,22 @@ files:
78
78
  - docs/project-plan/project_done.svg
79
79
  - docs/project-plan/project_in_progress.svg
80
80
  - docs/project-plan/project_todo.svg
81
- - lib/base_process.rb
82
- - lib/dsl_folder_watcher.rb
83
- - lib/dsl_interpreter.rb
84
- - lib/dsl_process_data.rb
85
81
  - lib/klue/langcraft.rb
86
82
  - lib/klue/langcraft/dsl/interpreter.rb
83
+ - lib/klue/langcraft/dsl/klue_runner.rb
87
84
  - lib/klue/langcraft/dsl/process_data_pipeline.rb
88
85
  - lib/klue/langcraft/dsl/process_matcher.rb
89
86
  - lib/klue/langcraft/dsl/processor_config.rb
90
87
  - lib/klue/langcraft/dsl/processors/file_collector_processor.rb
91
88
  - lib/klue/langcraft/dsl/processors/full_name_processor.rb
92
89
  - lib/klue/langcraft/dsl/processors/processor.rb
90
+ - lib/klue/langcraft/dsl/watcher.rb
91
+ - lib/klue/langcraft/dsl/webhook.rb
93
92
  - lib/klue/langcraft/tokenizer-old-needs-revisit/-brief.md
94
93
  - lib/klue/langcraft/tokenizer-old-needs-revisit/parser.rb
95
94
  - lib/klue/langcraft/tokenizer-old-needs-revisit/sample_usage.rb
96
95
  - lib/klue/langcraft/tokenizer-old-needs-revisit/tokenizer.rb
97
96
  - lib/klue/langcraft/version.rb
98
- - lib/process_file_collector.rb
99
97
  - package-lock.json
100
98
  - package.json
101
99
  - sig/klue/langcraft.rbs
data/bin/dsl_watcher.rb DELETED
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
5
-
6
- require 'klue/langcraft'
7
-
8
- BASE_PATH = ARGV[0] || '/Users/davidcruwys/dev/appydave/klueless'
9
-
10
- DSLFolderWatcher.watch(BASE_PATH)
data/lib/base_process.rb DELETED
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # file: lib/base_process.rb
4
-
5
- class BaseProcess
6
- attr_reader :key
7
-
8
- def initialize(key)
9
- @key = key
10
- end
11
-
12
- def deep_match(input, predicate)
13
- matches = []
14
-
15
- # If the current input is a Hash, iterate over each key-value pair
16
- if input.is_a?(Hash)
17
-
18
- input.each do |key, value|
19
-
20
- # If the value matches the predicate, add it to matches
21
- if predicate.call(key, value)
22
- matches << value
23
- end
24
-
25
- # Continue searching deeper within the value
26
- matches.concat(deep_match(value, predicate))
27
- end
28
-
29
- # If the input is an Array, iterate over each item
30
- elsif input.is_a?(Array)
31
-
32
- input.each do |item|
33
-
34
- # Continue searching within each item of the array
35
- matches.concat(deep_match(item, predicate))
36
- end
37
- end
38
-
39
- matches
40
- end
41
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class DSLFolderWatcher
4
- def self.watch(folder_path)
5
- puts "Watching: #{folder_path}"
6
- listener = Listen.to(folder_path) do |modified, added, _removed|
7
- changes = (modified + added).uniq
8
-
9
- # DEBOUNCE CURRENTLY NOT WORKING
10
- # debounce_map = {}
11
- # debounce_interval = 1 # seconds
12
-
13
- changes.each do |file_path|
14
- next unless File.extname(file_path) == '.klue'
15
-
16
- puts file_path
17
-
18
- # debounce_map[file_path] ||= Time.now
19
- # next unless Time.now - debounce_map[file_path] >= debounce_interval
20
-
21
- # debounce_map[file_path] = Time.now
22
-
23
- base_name = file_path.gsub(/\.klue$/, '')
24
- input_file = "#{base_name}.klue"
25
- output_file = "#{base_name}.json"
26
-
27
- interpreter = DSLInterpreter.new
28
- if interpreter.process('', input_file, output_file)
29
- # Process the JSON data to add 'process-data' details
30
- dsl_processor = DSLProcessData.new
31
- dsl_processor.process('', output_file, output_file)
32
- # SKIP EXTEND FILE FOR NOW AND REWRITE THE OUTPUTFILE
33
- # dsl_processor.process('', output_file, extended_output_file)
34
-
35
- # interpreter.send_to_endpoint
36
- else
37
- puts 'Skipping further processing due to errors in DSL interpretation.'
38
- end
39
- end
40
-
41
- # Remove old entries from debounce_map to prevent memory bloat
42
- # debounce_map.each_key do |key|
43
- # debounce_map.delete(key) if Time.now - debounce_map[key] > debounce_interval * 2
44
- # end
45
- end
46
- listener.start
47
- puts "Wait for changes: #{folder_path}"
48
- sleep
49
- end
50
- end
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # ChatReferences:
4
- # - https://chatgpt.com/c/67064770-d524-8002-8344-3091e895d150
5
- # - https://chatgpt.com/c/6706289c-9b9c-8002-86e3-f9198c1c608a
6
- # - https://chatgpt.com/c/670dcd34-5dbc-8002-ad7a-d4df54a6a2e0
7
- #
8
- class DSLInterpreter
9
- def initialize
10
- @data = {}
11
- end
12
-
13
- # Capturing top-level DSL methods
14
- def method_missing(method_name, *args, &block)
15
- key = method_name
16
- value = process_args(args, block)
17
-
18
- # Append key-value to the current context of @data
19
- if @data[key]
20
- @data[key] = [@data[key]] unless @data[key].is_a?(Array)
21
- @data[key] << value
22
- else
23
- @data[key] = value
24
- end
25
- end
26
-
27
- # A method to handle parameters and nested blocks
28
- def process_args(args, block)
29
- data = {}
30
-
31
- # Handling positional and named parameters separately
32
- positional_args = []
33
- named_args = {}
34
-
35
- args.each do |arg|
36
- if arg.is_a?(Hash)
37
- named_args.merge!(arg)
38
- else
39
- positional_args << arg
40
- end
41
- end
42
-
43
- # Assign positional parameters generically
44
- positional_args.each_with_index do |arg, index|
45
- data[:"param#{index + 1}"] = arg
46
- end
47
-
48
- # Merge named parameters directly
49
- data.merge!(named_args)
50
-
51
- # Handling a nested block
52
- if block
53
- interpreter = DSLInterpreter.new
54
- interpreter.instance_eval(&block)
55
- data.merge!(interpreter.data)
56
- end
57
-
58
- data.empty? ? nil : data
59
- end
60
-
61
- # To access data after interpreting
62
- attr_reader :data
63
-
64
- # Reading file and evaluating as Ruby
65
- def process(base_path, input_file, output_file)
66
- file_path = File.join(base_path, input_file)
67
- content = File.read(file_path)
68
-
69
- # begin
70
- instance_eval(content)
71
- # rescue SyntaxError => e
72
- # puts "Syntax error in DSL file: #{input_file}"
73
- # puts "Error message: #{e.message}"
74
- # puts "Error occurred at line: #{e.backtrace.first}"
75
- # return false # Indicate that processing failed
76
- # rescue StandardError => e
77
- # puts "Error processing DSL file: #{input_file}"
78
- # puts "Error message: #{e.message}"
79
- # puts "Error occurred at: #{e.backtrace.first}"
80
- # return false # Indicate that processing failed
81
- # end
82
-
83
- output_path = File.join(base_path, output_file)
84
- File.write(output_path, JSON.pretty_generate(to_hash))
85
- true # Indicate that processing succeeded
86
- end
87
-
88
- # Convert to hash or JSON as required
89
- def to_hash
90
- @data
91
- end
92
-
93
- def to_json(*_args)
94
- @data.to_json
95
- end
96
-
97
- # Method to send data to an endpoint
98
- def send_to_endpoint
99
- root_key = @data.keys.first
100
- action_type = root_key.to_s
101
-
102
- uri = URI.parse("http://localhost:4567/dsl/#{action_type}")
103
- http = Net::HTTP.new(uri.host, uri.port)
104
- request = Net::HTTP::Post.new(uri.path, { 'Content-Type' => 'application/json' })
105
- payload = { action_type: action_type, data: @data }
106
- request.body = payload.to_json
107
-
108
- response = http.request(request)
109
- puts "Response: #{response.code} - #{response.message}"
110
- puts "Endpoint: #{uri}"
111
- end
112
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class DSLProcessData
4
- PROCESSORS = [{ file_collector: ProcessFileCollector }].freeze
5
-
6
- # Method to process the JSON file after initial evaluation
7
- def process(base_path, input_file, output_file)
8
- json_file_path = File.join(base_path, input_file)
9
- data = JSON.parse(File.read(json_file_path))
10
-
11
- # Loop through the processors and execute matching ones
12
- PROCESSORS.each do |processor_entry|
13
- key, processor_class = processor_entry.first
14
- processor = processor_class.new(key)
15
-
16
- next unless processor.match?(data)
17
-
18
- result = processor.execute(data)
19
-
20
- data['process-data'] ||= {}
21
-
22
- result.each do |key, result|
23
- data['process-data'][key.to_s] = result unless result.empty?
24
- end
25
- end
26
-
27
- # Write the updated JSON data to an extended file
28
- extended_output_file = File.join(base_path, output_file)
29
- File.write(extended_output_file, JSON.pretty_generate(data))
30
- end
31
- end
@@ -1,92 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # file: lib/process_file_collector.rb
4
-
5
- class ProcessFileCollector < BaseProcess
6
- def initialize(key)
7
- super
8
- @found = nil
9
- # @matcher = ->(key, value) { key.to_s == 'file_collector' && value.is_a?(Hash) }
10
- @matcher = lambda do |key, value|
11
- if key.to_s == 'file_collector'
12
- if value.is_a?(Array)
13
- value.any? { |v| v.is_a?(Hash) }
14
- else
15
- value.is_a?(Hash)
16
- end
17
- else
18
- false
19
- end
20
- end
21
- end
22
-
23
- def match?(input)
24
- @found = deep_match(input, @matcher)
25
- !@found.empty?
26
- end
27
-
28
- def execute(_input)
29
- # Iterate over each `file_collector` found and process individually
30
- results = {}
31
-
32
- @found.each do |data|
33
- next unless data.is_a?(Hash)
34
-
35
- # Extract the `as` key if present
36
- as_key = data['as']
37
-
38
- working_directory = File.expand_path(data['root'])
39
-
40
- options = Appydave::Tools::GptContext::Options.new(
41
- working_directory: working_directory,
42
- include_patterns: extract_patterns(data.dig('files', 'include')),
43
- exclude_patterns: extract_patterns(data.dig('files', 'exclude')),
44
- format: 'json',
45
- line_limit: data['line_length']
46
- )
47
-
48
- collector = Appydave::Tools::GptContext::FileCollector.new(options)
49
- json = collector.build
50
-
51
- # Structuring the result under `process-data` with `as` as key
52
- result_data = {
53
- type: 'file_collector',
54
- data: {
55
- working_directory: working_directory,
56
- files: JSON.parse(json)
57
- }
58
- }
59
-
60
- # If `as` key exists, use it to store under process-data with that identifier
61
- if as_key
62
- results[as_key] = result_data
63
- else
64
- # Generate a unique key if no `as` key is defined
65
- unique_key = "file_collector_#{results.size + 1}"
66
- results[unique_key] = result_data
67
- end
68
- end
69
-
70
- results
71
- rescue SyntaxError, NameError, NoMethodError => e
72
- puts "Ruby evaluation error in ProcessFileCollector: #{e.message}"
73
- puts "Error occurred at: #{e.backtrace.first}"
74
- {}
75
- rescue StandardError => e
76
- puts "Unexpected error in ProcessFileCollector: #{e.message}"
77
- puts e.backtrace.join("\n")
78
- {}
79
- end
80
-
81
- private
82
-
83
- def extract_patterns(files_data)
84
- if files_data.is_a?(Hash)
85
- [files_data['param1']]
86
- elsif files_data.is_a?(Array)
87
- files_data.map { |entry| entry['param1'] }
88
- else
89
- []
90
- end
91
- end
92
- end