klue-langcraft 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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