k_manager 0.0.13 → 0.0.22

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/Gemfile +18 -0
  4. data/Rakefile +2 -0
  5. data/docs/flow.drawio +16 -0
  6. data/exe/k_manager +20 -0
  7. data/k_manager.gemspec +6 -0
  8. data/lib/k_manager/area.rb +47 -0
  9. data/lib/k_manager/document_factory.rb +74 -0
  10. data/lib/k_manager/manager.rb +58 -0
  11. data/lib/k_manager/overview/dashboard.rb +187 -0
  12. data/lib/k_manager/overview/dump_json.rb +35 -0
  13. data/lib/k_manager/overview/models.rb +76 -0
  14. data/lib/k_manager/overview/queries.rb +53 -0
  15. data/lib/k_manager/resources/base_resource.rb +189 -52
  16. data/lib/k_manager/resources/file_resource.rb +80 -58
  17. data/lib/k_manager/resources/{ruby_file_resource.rb → file_resources/ruby_file_resource.rb} +0 -0
  18. data/lib/k_manager/resources/{unknown_file_resource.rb → file_resources/unknown_file_resource.rb} +0 -0
  19. data/lib/k_manager/resources/mem_resource.rb +17 -0
  20. data/lib/k_manager/resources/resource_document_factory.rb +119 -0
  21. data/lib/k_manager/resources/resource_factory.rb +28 -0
  22. data/lib/k_manager/resources/resource_manager.rb +216 -0
  23. data/lib/k_manager/resources/resource_set.rb +90 -0
  24. data/lib/k_manager/resources/web_resource.rb +113 -0
  25. data/lib/k_manager/version.rb +1 -1
  26. data/lib/k_manager/watcher.rb +75 -0
  27. data/lib/k_manager/{x_project.rb → x_resource_documents/x_project.rb} +0 -0
  28. data/lib/k_manager/{x_project_manager.rb → x_resource_documents/x_project_manager.rb} +0 -0
  29. data/lib/k_manager/{x_register.rb → x_resource_documents/x_register.rb} +0 -0
  30. data/lib/k_manager.rb +93 -20
  31. data/tasks/watch.rake +113 -0
  32. metadata +70 -24
  33. data/Assessment1.md +0 -127
  34. data/Assessment2.md +0 -88
  35. data/lib/k_manager/create_document.rb +0 -31
  36. data/lib/k_manager/documents/basic_document.rb +0 -21
  37. data/lib/k_manager/documents/builder_document.rb +0 -18
  38. data/lib/k_manager/documents/document_taggable.rb +0 -94
  39. data/lib/k_manager/documents/model_document.rb +0 -19
  40. data/lib/k_manager/project.rb +0 -50
  41. data/lib/k_manager/resources/csv_file_resource.rb +0 -27
  42. data/lib/k_manager/resources/factories/document_factory.rb +0 -52
  43. data/lib/k_manager/resources/json_file_resource.rb +0 -22
  44. data/lib/k_manager/resources/yaml_file_resource.rb +0 -21
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KManager
4
+ # TODO: Write tests
5
+
6
+ # Usage1:
7
+ # manager = ResourceManager.new
8
+ # manager.add_resource('file:///david.csv')
9
+ # manager.add_resource('file:///david.txt', content_type: :json)
10
+ # manager.add_resource('https://gist.github.com/12345/david.csv', content_type: :csv)
11
+ # manager.load_resource_content
12
+ #
13
+ # Usage2:
14
+ # manager = ResourceManager.new
15
+ # manager.fileset.add('**/*.csv').add('**/*.json').add('lib/*.rb')
16
+ # manager.add_resources
17
+ # manager.load_resource_content
18
+ #
19
+ #
20
+ # Usage KWatcher
21
+ # WatchingDirctory('abc') do |path|
22
+ # manager.update_resource(path)
23
+ # end
24
+
25
+ # Example Director
26
+ # KDoc.diagram(:k_resource) do
27
+
28
+ # component(:resource_manager) do
29
+ # attr_rw(:resources)
30
+ # attr_rw(:fileset)
31
+
32
+ # method(:add_resource, description: "I will add a resource to the manager") do
33
+ # param(:resource_uri, description: 'xxxx')
34
+ # end
35
+
36
+ # method(:add_resource, description: "I will add a collection of resources to the manager via fileset or webset")
37
+ # method(:load_resource_content)
38
+ # end
39
+
40
+ # def on_action
41
+ # build_drawio("#{self.name}_class" , model: self.data, style: :class_diagram)
42
+ # build_drawio("#{self.name}_component" , model: self.data, style: :component_diagram)
43
+ # build_drawio("#{self.name}_swim" , model: self.data, style: :swimlane_diagram)
44
+ # end
45
+ # end
46
+
47
+ module Resources
48
+ class ResourceManager
49
+ extend Forwardable
50
+
51
+ include KLog::Logging
52
+ include KDoc::Guarded
53
+
54
+ attr_accessor :area
55
+
56
+ attr_accessor :fileset
57
+ attr_accessor :webset
58
+ attr_accessor :memset
59
+
60
+ # Resource set is built using file, web and memory resources
61
+ attr_accessor :resource_set
62
+
63
+ def initialize(area)
64
+ @area = area
65
+
66
+ @fileset = KFileset::FileSet.new
67
+ @webset = nil # TODO: when ready to implement URL based resources
68
+ @memset = nil # TODO: when ready to implement dynamic memory resources
69
+
70
+ @resource_factory = KManager::Resources::ResourceFactory.new
71
+ @resource_set = KManager::Resources::ResourceSet.new(area)
72
+ end
73
+
74
+ def_delegators :resource_set, :resources, :find_by_uri
75
+
76
+ # def resources
77
+ # resource_set.resources
78
+ # end
79
+
80
+ def resource_models
81
+ resource_set.resources.map(&:as_model)
82
+ end
83
+
84
+ def resource_changed(resource_uri, state)
85
+ create_resource(resource_uri) if state == :created
86
+ update_resource(resource_uri) if state == :updated
87
+ delete_resource(resource_uri) if state == :deleted
88
+
89
+ log_any_messages unless valid?
90
+ end
91
+
92
+ def create_resource(resource_uri)
93
+ # TODO: skip if not whitelisted
94
+
95
+ # warn if the resource already existed (this should not happen)
96
+ # if fileset.whitelist
97
+ # build resource
98
+ # add resource to fileset
99
+ end
100
+
101
+ def update_resource(resource_uri)
102
+ # TODO: skip if not whitelisted
103
+
104
+ resource = resource_set.find_by_uri(resource_uri)
105
+
106
+ return warn("Resource not in Resource Set - Skipping: #{resource_uri.path}") unless resource
107
+
108
+ replace_resource = resource.recreate(resource)
109
+ replace_resource.fire_action(:load_content)
110
+ replace_resource.fire_action(:register_document)
111
+ replace_resource.fire_action(:load_document)
112
+ resource_set.replace(replace_resource)
113
+ end
114
+
115
+ def delete_resource(resource_uri)
116
+ # TODO: skip if not whitelisted
117
+
118
+ # find resource
119
+ # if found, remove it
120
+ end
121
+
122
+ def add_resource_expand_path(file, **opts)
123
+ add_resource(File.expand_path(file), **opts)
124
+ end
125
+
126
+ # Add a resource based on a resource_uri
127
+ #
128
+ # @param [URI|String] resource_uri Path to the resource, if the path uses file:/// then it will add a file resource, if the path http: or https: then a web resource will be added
129
+ # TODO: Test File URI: relative_path
130
+ # TODO: Test File URI: absolute_path
131
+ # TODO: Test URI
132
+ # TODO: Test URI (Web)
133
+ # TODO: Test URI (File)
134
+ def add_resource(resource_uri, **opts)
135
+ resource_set.add(build_resource(resource_uri, **opts))
136
+ end
137
+
138
+ # TODO: Not sure if this is right
139
+ def build_resource(resource_uri, **opts)
140
+ resource_uri = parse_uri(resource_uri)
141
+ @resource_factory.instance(resource_uri, **opts)
142
+ end
143
+
144
+ def add_resources
145
+ add_web_resources
146
+ add_file_resources
147
+ end
148
+
149
+ # def update_resource(path)
150
+ # uri = path_to_uri(path)
151
+ # reset_existing_resource(uri)
152
+ # add_resource(uri)
153
+ # load_resource_content
154
+ # end
155
+
156
+ # Fire actions against all resources in this manager.
157
+ #
158
+ # @param [*Array<Symbol>] actions List of actions to run. [:load_content, :register_document, :load_document]
159
+ def fire_actions(*actions)
160
+ guard_action(actions)
161
+
162
+ load_content if actions.include?(:load_content)
163
+ register_documents if actions.include?(:register_document)
164
+ load_documents if actions.include?(:load_document)
165
+ end
166
+
167
+ def guard_action(actions)
168
+ actions.each do |action|
169
+ warn "ResourceManager.fire_actions - unknown action: #{action}" unless KManager::Resources::BaseResource.valid_action?(action)
170
+ end
171
+ end
172
+
173
+ def load_content
174
+ resources.each do |resource|
175
+ resource.fire_action(:load_content)
176
+ end
177
+ end
178
+
179
+ def register_documents
180
+ resources.each do |resource|
181
+ resource.fire_action(:register_document)
182
+ end
183
+ end
184
+
185
+ def load_documents
186
+ resources.each do |resource|
187
+ resource.fire_action(:load_document)
188
+ end
189
+ end
190
+
191
+ def debug
192
+ resources.each(&:debug)
193
+ end
194
+
195
+ private
196
+
197
+ def parse_uri(uri)
198
+ return uri if uri.is_a?(URI)
199
+ return URI.parse(uri) if uri =~ URI::ABS_URI # https://stackoverflow.com/questions/1805761/how-to-check-if-a-url-is-valid
200
+
201
+ URI.join('file:///', uri)
202
+ end
203
+
204
+ def add_web_resources
205
+ # TODO
206
+ # return if @webset.nil?
207
+ end
208
+
209
+ def add_file_resources
210
+ fileset.path_entries.each do |path_entry|
211
+ add_resource(path_entry.uri)
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KManager
4
+ # TODO: Write Tests
5
+
6
+ # A resource set holds a list of resources
7
+ #
8
+ # A resource could be a file, web-service, gist, ftp endpoint, memory object.
9
+ #
10
+ # ResourceSet is an internal component and is used by the ResourceManager
11
+ #
12
+ # The resource manager will create resources with the ResourceFactory and assign
13
+ # those resources to the ResourceSet
14
+ #
15
+ # The only supported resource types so far are:
16
+ # - File
17
+ #
18
+ # Resources can be registered with the ResourceSet using register_* methods
19
+ #
20
+ # somepath
21
+ # somepath/my_dsls
22
+ # somepath/my_dsls/path1
23
+ # somepath/my_dsls/path2
24
+ # somepath/my_dsls/path2/child
25
+ # somepath/my_dsls/path2/old (skip this path)
26
+ # somepath/my_data/
27
+ # somepath/my_templates
28
+ module Resources
29
+ class ResourceSet
30
+ include KLog::Logging
31
+
32
+ attr_reader :area
33
+ attr_reader :resources
34
+
35
+ def initialize(area)
36
+ @area = area
37
+ @resources = []
38
+ end
39
+
40
+ def add(resource)
41
+ return log.warn "Resource already added: #{resource.resource_path}" if find(resource)
42
+
43
+ resource.area = area
44
+ resources << resource
45
+ resource
46
+ end
47
+
48
+ def replace(resource)
49
+ index = find_index(resource)
50
+ return log.warn "Resource to replace does not exist: #{resource.resource_path}" unless index
51
+
52
+ resource.area = area
53
+ resources[index] = resource
54
+ resource
55
+ end
56
+
57
+ def add_resources(resource_list)
58
+ resource_list.each do |resource|
59
+ add(resource)
60
+ end
61
+ end
62
+
63
+ def debug
64
+ resources.each(&:debug)
65
+ nil
66
+ end
67
+
68
+ def find_by_uri(resource_uri)
69
+ resources.find { |r| r.resource_path == resource_uri.path }
70
+ end
71
+
72
+ private
73
+
74
+ def find(resource)
75
+ index = find_index(resource)
76
+ return nil unless index
77
+
78
+ resources[index] # .find { |r| r.resource_path == resource.resource_path }
79
+ end
80
+
81
+ def find_index(resource)
82
+ resources.index { |r| r.resource_path == resource.resource_path }
83
+ end
84
+
85
+ # def to_h
86
+ # resources.map(&:to_h)
87
+ # end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KManager
4
+ module Resources
5
+ require 'handlebars/helpers/string_formatting/dasherize'
6
+
7
+ # A web resource represents content that is loaded via a web URI.
8
+ #
9
+ # Web resources do not support watchers and so if you want to handle
10
+ # content changes then you will either need to poll the resource periodically
11
+ # or have a server with open channel for web-hooks.
12
+ class WebResource < KManager::Resources::BaseResource
13
+ include KLog::Logging
14
+
15
+ def initialize(uri, **opts)
16
+ warn('URI::HTTP/HTTPS type is expected for Web Resource') unless uri.is_a?(URI::HTTP)
17
+ super(uri, **opts)
18
+ log_any_messages unless valid?
19
+ end
20
+
21
+ # Infer key is the file name without the extension stored in dash-case
22
+ def infer_key
23
+ last_segment = uri.path.split('/').last
24
+ Handlebars::Helpers::StringFormatting::Snake.new.parse(last_segment)
25
+ end
26
+
27
+ def default_scheme
28
+ :https
29
+ end
30
+
31
+ def resource_path
32
+ @resource_path ||= source_path
33
+ end
34
+
35
+ def resource_relative_path
36
+ uri.path
37
+ end
38
+
39
+ def resource_valid?
40
+ return @resource_valid if defined? @resource_valid
41
+
42
+ @resource_valid = url_exist?(source_path)
43
+ end
44
+
45
+ def load_content
46
+ if resource_valid?
47
+ begin
48
+ @content = fetch(source_path)
49
+ rescue StandardError => e
50
+ log.error e
51
+ end
52
+ else
53
+ guard("Source url not valid: #{resource_path}")
54
+ end
55
+ end
56
+
57
+ def attribute_values(prefix = nil)
58
+ result = super(prefix)
59
+ result["#{prefix}path".to_sym] = resource_path
60
+ result["#{prefix}relative_path".to_sym] = resource_relative_path
61
+ result["#{prefix}exist".to_sym] = resource_valid?
62
+ result
63
+ end
64
+
65
+ def debug
66
+ super do
67
+ log.kv 'infer_key' , infer_key , 20
68
+ log.kv 'url' , source_path , 20
69
+ log.kv 'resource_path' , resource_path , 20
70
+ log.kv 'resource_valid?' , resource_valid? , 20
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ # rubocop:disable Metrics/AbcSize
77
+ def url_exist?(url_str, limit = 10)
78
+ raise ArgumentError, 'too many HTTP redirects' if limit.zero?
79
+
80
+ url = URI.parse(url_str)
81
+ req = Net::HTTP.new(url.host, url.port)
82
+ req.use_ssl = (url.scheme == 'https')
83
+ res = req.request_head(url.path || '/')
84
+ if res.is_a?(Net::HTTPRedirection)
85
+ url_exist?(res['location'], limit - 1) # Go after any redirect and make sure you can access the redirected URL
86
+ else
87
+ !%w[4 5].include?(res.code[0]) # Not from 4xx or 5xx families
88
+ end
89
+ rescue Errno::ENOENT
90
+ false # false if can't find the server
91
+ end
92
+ # rubocop:enable Metrics/AbcSize
93
+
94
+ def fetch(url_str, limit = 10)
95
+ raise ArgumentError, 'too many HTTP redirects' if limit.zero?
96
+
97
+ url = URI.parse(url_str)
98
+ res = Net::HTTP.get_response(url)
99
+
100
+ case res
101
+ when Net::HTTPSuccess
102
+ res.body
103
+ when Net::HTTPRedirection
104
+ location = res['location']
105
+ puts "redirected to #{location}"
106
+ fetch(location, limit - 1)
107
+ else
108
+ res.value
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KManager
4
- VERSION = '0.0.13'
4
+ VERSION = '0.0.22'
5
5
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'filewatcher'
4
+ require 'io/console'
5
+
6
+ module KManager
7
+ # NOTE: Does Watcher belong in this GEM?
8
+ class Watcher
9
+ include KLog::Logging
10
+
11
+ attr_reader :watch_folder
12
+ attr_reader :boot_file
13
+
14
+ def initialize(watch_folder, boot_file)
15
+ @watch_folder = watch_folder
16
+ @boot_file = boot_file
17
+ end
18
+
19
+ # process_created_file(filename) if event == :created
20
+ # process_updated_file(filename) if event == :updated # || event == :created
21
+ # process_deleted_file(filename) if event == :deleted
22
+
23
+ # rubocop:disable Lint/RescueException
24
+ def start
25
+ bootup
26
+
27
+ update_dashboard
28
+
29
+ Filewatcher.new(watch_folder).watch do |changes|
30
+ changes.each do |filename, event|
31
+ clear_screen
32
+
33
+ puts "File #{event}: #{filename}"
34
+
35
+ uri = URI::File.build(host: nil, path: filename)
36
+ KManager.resource_changed(uri, event)
37
+
38
+ update_dashboard
39
+ end
40
+ end
41
+ rescue Exception => e
42
+ # TODO: Make style a setting: :message, :short, (whatever the last one is)
43
+ log.exception(e, style: :short)
44
+ end
45
+ # rubocop:enable Lint/RescueException
46
+
47
+ private
48
+
49
+ def bootup
50
+ clear_screen
51
+
52
+ content = File.read(boot_file)
53
+ Object.class_eval(content, boot_file)
54
+ end
55
+
56
+ def update_dashboard
57
+ dashboard = KManager::Overview::Dashboard.new(KManager.manager)
58
+ # dashboard.areas
59
+ dashboard.resources
60
+ dashboard.documents
61
+ end
62
+
63
+ def update_load_path(filename)
64
+ dirname = File.dirname(filename)
65
+
66
+ # This needs to be in detailed logging
67
+ $LOAD_PATH.unshift(dirname) unless $LOAD_PATH.find { |path| path.start_with?(dirname) }
68
+ end
69
+
70
+ def clear_screen
71
+ puts "\n" * 70
72
+ $stdout.clear_screen
73
+ end
74
+ end
75
+ end
data/lib/k_manager.rb CHANGED
@@ -1,44 +1,117 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'csv'
4
+ require 'dry-struct'
5
+ require 'forwardable'
6
+ require 'k_log'
3
7
  require 'k_doc'
8
+ require 'k_fileset'
4
9
  require 'k_builder'
5
10
  require 'k_ext/github'
6
- require 'k_log'
7
11
 
8
- require 'k_manager/create_document'
12
+ # IS THIS NEEDED? this was used for infer_key
13
+ require 'handlebars/helpers/string_formatting/dasherize'
14
+ require 'handlebars/helpers/string_formatting/snake'
15
+
9
16
  require 'k_manager/version'
10
17
  require 'k_manager/configuration/project_config'
11
- require 'k_manager/documents/document_taggable'
12
- require 'k_manager/documents/basic_document'
13
- require 'k_manager/documents/model_document'
14
- require 'k_manager/documents/builder_document'
18
+ require 'k_manager/overview/models'
19
+ require 'k_manager/overview/queries'
20
+ require 'k_manager/overview/dump_json'
21
+ require 'k_manager/overview/dashboard'
22
+ require 'k_manager/resources/resource_set'
15
23
  require 'k_manager/resources/base_resource'
16
24
  require 'k_manager/resources/file_resource'
17
- require 'k_manager/resources/csv_file_resource'
18
- require 'k_manager/resources/json_file_resource'
19
- require 'k_manager/resources/ruby_file_resource'
20
- require 'k_manager/resources/yaml_file_resource'
21
- require 'k_manager/resources/unknown_file_resource'
22
- require 'k_manager/project'
25
+ require 'k_manager/resources/web_resource'
26
+ require 'k_manager/resources/mem_resource'
27
+ require 'k_manager/resources/resource_document_factory'
28
+ require 'k_manager/resources/resource_factory'
29
+ require 'k_manager/resources/resource_manager'
30
+ require 'k_manager/document_factory'
31
+ require 'k_manager/manager'
32
+ require 'k_manager/area'
23
33
 
24
34
  module KManager
25
- extend CreateDocument
26
-
27
35
  # raise KManager::Error, 'Sample message'
28
36
  class Error < StandardError; end
29
37
 
30
38
  class << self
39
+ extend Forwardable
40
+
41
+ # ----------------------------------------------------------------------
42
+ # Concurrency management for currently focused resource
43
+ # ----------------------------------------------------------------------
44
+
45
+ attr_reader :current_resource
46
+
47
+ def resource_mutex
48
+ @resource_mutex ||= Mutex.new
49
+ end
50
+
51
+ def for_resource(resource = nil)
52
+ resource_mutex.synchronize do
53
+ @current_resource = resource
54
+ yield(current_resource)
55
+ @current_resource = nil
56
+ end
57
+ end
58
+
59
+ def for_current_resource
60
+ raise KManager::Error, 'Attempting to yield current_resource, when a different thread has the lock?' unless resource_mutex.owned?
61
+
62
+ yield(@current_resource)
63
+ end
64
+
65
+ # ----------------------------------------------------------------------
66
+ # Debug Flags
67
+ # ----------------------------------------------------------------------
68
+
69
+ def debug_state
70
+ return @debug_state if defined? @debug_state
71
+
72
+ @debug_state = :disabled
73
+ end
74
+
75
+ def debug_enable
76
+ @debug_state = :enabled
77
+ end
78
+
79
+ def debug?
80
+ debug_state == :enabled
81
+ end
82
+
83
+ # ----------------------------------------------------------------------
84
+ # Manager facade methods
85
+ # ----------------------------------------------------------------------
86
+
87
+ def manager
88
+ @manager ||= Manager.new
89
+ end
90
+
91
+ def reset
92
+ # @resource_mutex.unlock if @resource_mutex
93
+ # @current_resource = nil
94
+ @manager = Manager.new
95
+ end
96
+
97
+ def_delegators :manager, :areas, :add_area, :fire_actions, :resource_changed
98
+
99
+ # ----------------------------------------------------------------------
100
+ # Document factory facade methods
101
+ # ----------------------------------------------------------------------
102
+
103
+ def document_factory
104
+ @document_factory ||= DocumentFactory.new
105
+ end
106
+
107
+ def_delegators :document_factory, :model, :csv, :json, :yaml
108
+
109
+ # TODO: DEPRECATE or REFACTOR
31
110
  def new_project_config(&block)
32
111
  config = KManager::Configuration::ProjectConfig.new
33
112
  block.call(config) if block_given?
34
113
  config
35
114
  end
36
-
37
- # Instance of the currently focused resource
38
- # if document get created dynamically due to class_eval then they
39
- # can attach themselves to the currently focussed resource via
40
- # KManager.target_resource.add_document(document)
41
- attr_accessor :target_resource
42
115
  end
43
116
  end
44
117