k_doc 0.0.1 → 0.0.4

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: c6d0219141addaa6425e5135a40e128ed88deb1dc42dac3989c3e7cb4f52a92f
4
- data.tar.gz: 13baebe5946adcdc788f95dbef03c58bf4023a5b0c9c7ce0152565c9445e5df3
3
+ metadata.gz: b3ade2c96c7dd68a9b948f680c63a3a3f28d79f48a3808df328435054e32048f
4
+ data.tar.gz: f932c466c175cd9258220b370ea040982e2fd57be560fd816c8a60818d4344c6
5
5
  SHA512:
6
- metadata.gz: 4009d089e065d75155cbf542ac44bb584f50e7e67318201e3b10a89bd726117e03b1ee91ef9ad019e5cac7a6937ef73f5a740677393fdf9cac0c1f1324f15214
7
- data.tar.gz: 2afd8c789286539ff68decb4c3c971bd5175c48055abc0a6b524cd8347c23dc9a77c8c29a9316b9d8f10ef1c27b167cb8e7748afa0ff8f8ef79233620435fcb9
6
+ metadata.gz: 6f18c5daebd800c3e3e33ce5c8ec882833cc64b97c7d8b415c6078abed1c7fce76a6bb59f53afe51511035e77e198fdd1e106cf746dcff6fa7a96a3d0af88128
7
+ data.tar.gz: 36ab77e3f217d639bc02f911b23674322ad0dd2c2e1aed0042f57195fda0b6b8f95e0119758e0c85f0bddb485b0ea77d73d2543b6c515b315bb5c5d95171ab77
data/.rubocop.yml CHANGED
@@ -44,6 +44,9 @@ Layout/LineLength:
44
44
  Lint/UnusedMethodArgument:
45
45
  AllowUnusedKeywordArguments: true
46
46
 
47
+ Style/Documentation:
48
+ Enabled: false
49
+
47
50
  Style/BlockComments:
48
51
  Enabled: false
49
52
  Include:
data/Guardfile ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :bundler, cmd: 'bundle install' do
4
+ watch('Gemfile')
5
+ watch('k_doc.gemspec')
6
+ end
7
+
8
+ group :green_pass_then_cop, halt_on_fail: true do
9
+ guard :rspec, cmd: 'bundle exec rspec -f doc' do
10
+ require 'guard/rspec/dsl'
11
+ dsl = Guard::RSpec::Dsl.new(self)
12
+
13
+ # RSpec files
14
+ rspec = dsl.rspec
15
+ watch(rspec.spec_helper) { rspec.spec_dir }
16
+ watch(rspec.spec_support) { rspec.spec_dir }
17
+ watch(rspec.spec_files)
18
+
19
+ # Ruby files
20
+ ruby = dsl.ruby
21
+ dsl.watch_spec_files_for(ruby.lib_files)
22
+ watch(%r{^lib/k_doc/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
23
+ watch(%r{^lib/k_doc/commands/(.+)\.rb$}) { |m| "spec/unit/commands/#{m[1]}_spec.rb" }
24
+ end
25
+
26
+ guard :rubocop, all_on_start: false, cli: ['--format', 'clang'] do
27
+ watch(/{.+\.rb$/)
28
+ watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
29
+ end
30
+ end
data/README.md CHANGED
@@ -26,16 +26,23 @@ gem install k_doc
26
26
 
27
27
  ### Main Story
28
28
 
29
-
29
+ As a Developer, I need flexible data structures defined in DSL, so can model rich documents
30
30
 
31
31
  See all [stories](./STORIES.md)
32
32
 
33
-
34
33
  ## Usage
35
34
 
36
35
  See all [usage examples](./USAGE.md)
37
36
 
37
+ ### Basic Example
38
+
39
+ #### Basic example
38
40
 
41
+ Description for a basic example to be featured in the main README.MD file
42
+
43
+ ```ruby
44
+ class SomeRuby; end
45
+ ```
39
46
 
40
47
  ## Development
41
48
 
@@ -45,7 +52,7 @@ Checkout the repo
45
52
  git clone klueless-io/k_doc
46
53
  ```
47
54
 
48
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
55
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
49
56
 
50
57
  You can also run `bin/console` for an interactive prompt that will allow you to experiment.
51
58
 
data/STORIES.md ADDED
@@ -0,0 +1,44 @@
1
+ # K Doc
2
+
3
+ > KDoc provides a document in the form a DSL that contains flexible key/value and tabular data
4
+
5
+ As a Developer, I need flexible data structures defined in DSL, so can model rich documents
6
+
7
+ ## Development radar
8
+
9
+ ### Stories next on list
10
+
11
+ As a Developer, I need flexible data structures defined in DSL, so can model rich documents
12
+
13
+ ### Tasks next on list
14
+
15
+ Setup RubyGems and RubyDoc
16
+
17
+ - Build and deploy gem to [rubygems.org](https://rubygems.org/gems/k_doc)
18
+ - Attach documentation to [rubydoc.info](https://rubydoc.info/github/to-do-/k_doc/master)
19
+
20
+ Setup GitHub Action (test and lint)
21
+
22
+ - Setup Rspec action
23
+ - Setup RuboCop action
24
+
25
+ ## Stories and tasks
26
+
27
+ ### Tasks - completed
28
+
29
+ Setup project management, requirement and SCRUM documents
30
+
31
+ - Setup readme file
32
+ - Setup user stories and tasks
33
+ - Setup a project backlog
34
+ - Setup an examples/usage document
35
+
36
+ Setup new Ruby GEM
37
+
38
+ - Build out a standard GEM structure
39
+ - Add automated semantic versioning
40
+ - Add Rspec unit testing framework
41
+ - Add RuboCop linting
42
+ - Add Guard for automatic watch and test
43
+ - Add GitFlow support
44
+ - Add GitHub Repository
data/USAGE.md ADDED
@@ -0,0 +1,19 @@
1
+ # K Doc
2
+
3
+ > KDoc provides a document in the form a DSL that contains flexible key/value and tabular data
4
+
5
+ As a Developer, I need flexible data structures defined in DSL, so can model rich documents
6
+
7
+ ## Usage
8
+
9
+ ### Sample Classes
10
+
11
+ #### Simple example
12
+
13
+ Description for a simple example that shows up in the USAGE.MD
14
+
15
+ ```ruby
16
+ class SomeRuby
17
+ def initialize; end
18
+ end
19
+ ```
data/k_doc.gemspec CHANGED
@@ -38,5 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.require_paths = ['lib']
39
39
  # spec.extensions = ['ext/k_doc/extconf.rb']
40
40
 
41
+ spec.add_dependency 'k_log' , '~> 0.0.0'
42
+ spec.add_dependency 'k_util' , '~> 0.0.0'
41
43
  # spec.add_dependency 'tty-box', '~> 0.5.0'
42
44
  end
data/lib/k_doc.rb CHANGED
@@ -1,10 +1,52 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'securerandom'
4
+
5
+ require 'logger'
6
+ require 'table_print'
7
+ require 'k_log'
8
+ require 'k_util'
9
+ require 'k_log/log_formatter'
10
+ require 'k_log/log_helper'
11
+ require 'k_log/log_util'
12
+
3
13
  require 'k_doc/version'
14
+ require 'k_doc/data'
15
+ require 'k_doc/document'
16
+ require 'k_doc/fake_opinion'
17
+ require 'k_doc/settings'
18
+ require 'k_doc/table'
19
+ require 'k_doc/util'
4
20
 
5
21
  module KDoc
6
22
  # raise KDoc::Error, 'Sample message'
7
23
  class Error < StandardError; end
8
24
 
9
- # Your code goes here...
25
+ class << self
26
+ # Factory method to create a new document
27
+ def doc(key = nil, **options, &block)
28
+ doc = KDoc::Document.new(key, **options, &block)
29
+ doc.execute_block
30
+ doc
31
+ end
32
+
33
+ attr_accessor :opinion
34
+ attr_accessor :util
35
+ attr_accessor :log
36
+ end
37
+
38
+ KDoc.opinion = KDoc::FakeOpinion.new
39
+ KDoc.util = KDoc::Util.new
40
+
41
+ # Need to move this into a KLog factory
42
+ def self.configure_logger
43
+ logger = Logger.new($stdout)
44
+ logger.level = Logger::DEBUG
45
+ logger.formatter = KLog::LogFormatter.new
46
+ KLog::LogUtil.new(logger)
47
+ end
48
+
49
+ # KDoc.log = configure_logger
10
50
  end
51
+
52
+ L = KDoc.configure_logger
data/lib/k_doc/data.rb ADDED
@@ -0,0 +1,258 @@
1
+ # frozen_string_literal: true
2
+
3
+ # module KDoc
4
+ # # TODO
5
+ # # Missing tests around errors
6
+ # # Make sure that error writes to resource or document appropriately
7
+ # # Puts errors onto a project manager pipeline so that they can be be printed out after the documents
8
+ # #
9
+ # # General purpose document DSL
10
+ # #
11
+ # # Made up of 0 or more setting groups and table groups
12
+ # class Data
13
+ # extend Forwardable
14
+
15
+ # attr_reader :key
16
+ # attr_reader :type
17
+ # attr_reader :namespace
18
+ # attr_reader :options
19
+ # attr_reader :error
20
+
21
+ # # State of document
22
+ # # - :initializing
23
+ # # - :initialized
24
+ # # - :loading
25
+ # # - :loaded
26
+ # # - :executing
27
+ # # - :executed
28
+ # attr_reader :state
29
+
30
+ # # Shortcut to formatter
31
+ # attr_reader :f
32
+
33
+ # attr_accessor :resource
34
+
35
+ # def_delegator :resource, :project
36
+
37
+ # def state=(state)
38
+ # @state = state
39
+ # # if [:initialized, :loaded, :executed].include?(state) &&
40
+ # # (project.nil? || project.name == 'k_dsl')
41
+ # # # pname = project.nil? ? '' : "#{project&.name} "
42
+ # # L.kv "#{unique_key} - state", state
43
+ # # end
44
+ # @state
45
+ # end
46
+
47
+ # # Create document
48
+ # #
49
+ # # @param [String|Symbol] name Name of the document
50
+ # # @param args[0] Type of the document, defaults to KDsl.config.default_document_type if not set
51
+ # # @param default: Default value (using named params), as above
52
+ # def initialize(key = SecureRandom.alphanumeric(8), *args, **options, &block)
53
+ # @key = key
54
+ # @type = args.length.positive? ? args[0] || KDsl.config.default_document_type : KDsl.config.default_document_type
55
+
56
+ # @options = options || {}
57
+ # @namespace = options[:namespace] || ''
58
+ # default_data = options[:default_data] || {}
59
+
60
+ # @namespace = @namespace.to_s
61
+ # @error = nil
62
+
63
+ # self.state = :initializing
64
+
65
+ # # Most documents live within a hash, some tabular documents such as
66
+ # # CSV will use an []
67
+ # set_data(default_data)
68
+
69
+ # @f = KDsl::Util.format
70
+
71
+ # @block = block if block_given?
72
+
73
+ # self.state = :initialized
74
+ # end
75
+
76
+ # def execute_block(run_actions: nil)
77
+ # return if @block.nil?
78
+
79
+ # # The DSL actions method will only run on run_actions: true
80
+ # @run_actions = run_actions
81
+
82
+ # # if unique_key == 'template_options_entity'
83
+ # # L.kv '2:CLASS_ID', object_id
84
+ # # end
85
+ # if initialized?
86
+ # self.state = :loading
87
+ # instance_eval(&@block)
88
+ # self.state = :loaded
89
+ # end
90
+ # # if unique_key == 'template_options_entity'
91
+ # # L.kv '3:CLASS_ID', resource_document.object_id
92
+ # # end
93
+
94
+ # if loaded? && run_actions && respond_to?(:on_action)
95
+ # @state = :executed
96
+ # on_action
97
+ # end
98
+ # rescue KDsl::Error => e
99
+ # L.error('KDsl::Error in document')
100
+ # L.kv 'key', unique_key
101
+ # L.kv 'file', KDsl::Util.data.console_file_hyperlink(resource.file, resource.file)
102
+ # L.error(e.message)
103
+ # @error = e
104
+ # # L.heading "Invalid code block in document_dsl during registration: #{k_key}"
105
+ # # L.exception exception
106
+ # raise
107
+ # rescue StandardError => e
108
+ # L.error('Standard error in document')
109
+ # L.kv 'key', unique_key
110
+ # L.kv 'file', KDsl::Util.data.console_file_hyperlink(resource.file, resource.file)
111
+ # L.error(e.message)
112
+ # @error = e
113
+ # # L.exception exception2
114
+ # raise
115
+ # ensure
116
+ # @run_actions = nil
117
+ # return
118
+ # end
119
+
120
+ # def initialized?
121
+ # @state == :initialized
122
+ # end
123
+
124
+ # def loaded?
125
+ # @state == :loaded
126
+ # end
127
+
128
+ # def executed?
129
+ # @state == :executed
130
+ # end
131
+
132
+ # def unique_key
133
+ # @unique_key ||= KDsl::Util.dsl.build_unique_key(key, type, namespace)
134
+ # end
135
+
136
+ # def settings(key = nil, **options, &block)
137
+ # options ||= {}
138
+
139
+ # opts = {}.merge(@options) # Document Options
140
+ # .merge(options) # Settings Options
141
+
142
+ # settings = settings_instance(@data, key, parent: self, &block)
143
+ # settings.run_decorators(opts)
144
+ # settings
145
+ # end
146
+
147
+ # def table(key = :table, &block)
148
+ # # NEED to add support for run_decorators I think
149
+ # table_instance(@data, key, parent: self, &block)
150
+ # end
151
+ # alias rows table
152
+
153
+ # # Sweet add-on would be builders
154
+ # # def builder(key, &block)
155
+ # # # example
156
+ # # KDsl::Builder::Shotstack.new(@data, key, &block)
157
+ # # end
158
+
159
+ # def set_data(data)
160
+ # @data = data
161
+ # end
162
+
163
+ # def data
164
+ # @data.clone
165
+ # end
166
+
167
+ # def data_struct
168
+ # KDsl::Util.data.to_struct(data)
169
+ # end
170
+ # alias d data_struct
171
+
172
+ # def raw_data_struct
173
+ # KDsl::Util.data.to_struct(raw_data)
174
+ # end
175
+
176
+ # def get_node_type(node_name)
177
+ # node_name = KDsl::Util.data.clean_symbol(node_name)
178
+ # node_data = @data[node_name]
179
+
180
+ # raise KDsl::Error, "Node not found: #{node_name}" if node_data.nil?
181
+
182
+ # if node_data.keys.length == 2 && (node_data.key?('fields') && node_data.key?('rows'))
183
+ # :table
184
+ # else
185
+ # :settings
186
+ # end
187
+ # end
188
+
189
+ # # Removes any meta data eg. "fields" from a table and just returns the raw data
190
+ # def raw_data
191
+ # # REFACT, what if this is CSV, meaning it is just an array?
192
+ # # add specs
193
+ # result = data
194
+
195
+ # result.each_key do |key|
196
+ # # ANTI: get_node_type uses @data while we are using @data.clone here
197
+ # data[key] = if get_node_type(key) == :table
198
+ # result[key].delete('fields')
199
+ # else
200
+ # result[key]
201
+ # end
202
+ # end
203
+
204
+ # data
205
+ # end
206
+
207
+ # # Move this out to the logger function when it has been refactor
208
+ # def debug(include_header = false)
209
+ # debug_header if include_header
210
+
211
+ # # tp dsls.values, :k_key, :k_type, :state, :save_at, :last_at, :data, :last_data, :source, { :file => { :width => 150 } }
212
+ # # puts JSON.pretty_generate(data)
213
+ # L.o(raw_data_struct)
214
+ # end
215
+
216
+ # def debug_header
217
+ # L.heading self.class.name
218
+ # L.kv 'key', key
219
+ # L.kv 'type', type
220
+ # L.kv 'namespace', namespace
221
+ # L.kv 'error', error
222
+ # L.kv 'state', state
223
+ # L.kv 'respond_to?(:on_import)', respond_to?(:on_import)
224
+ # L.kv 'respond_to?(:david)', respond_to?(:david)
225
+ # david if respond_to?(:david)
226
+ # # L.kv 'INITALIZED', resource_document.initialized?
227
+ # # L.kv 'EXECUTED', resource_document.executed?
228
+
229
+ # options&.keys.reject { |k| k == :namespace }&.each do |key|
230
+ # L.kv key, options[key]
231
+ # end
232
+
233
+ # L.line
234
+ # end
235
+
236
+ # # Helpers that often get called by extensions
237
+
238
+ # def project
239
+ # project ||= resource&.project
240
+ # end
241
+
242
+ # # Warning message
243
+ # def warn(message)
244
+ # L.warn message
245
+ # nil
246
+ # end
247
+
248
+ # private
249
+
250
+ # def settings_instance(data, key, **options, &block)
251
+ # KDsl.config.settings_class.new(data, key, **options, &block)
252
+ # end
253
+
254
+ # def table_instance(data, key, **options, &block)
255
+ # KDsl.config.table_class.new(data, key, **options, &block)
256
+ # end
257
+ # end
258
+ # end
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KDoc
4
+ # General purpose document DSL
5
+ #
6
+ # Made up of 0 or more setting groups and table groups
7
+ class Document
8
+ attr_reader :key
9
+ attr_reader :type
10
+ attr_reader :namespace
11
+ attr_reader :options
12
+ attr_reader :error
13
+
14
+ # Create document
15
+ #
16
+ # @param [String|Symbol] name Name of the document
17
+ # @param args[0] Type of the document, defaults to KDoc:: FakeOpinion.new.default_document_type if not set
18
+ # @param default: Default value (using named params), as above
19
+ def initialize(key = SecureRandom.alphanumeric(8), **options, &block)
20
+ initialize_attributes(key, **options)
21
+
22
+ @block = block if block_given?
23
+ end
24
+
25
+ def execute_block(run_actions: nil)
26
+ return if @block.nil?
27
+
28
+ # The DSL actions method will only run on run_actions: true
29
+ @run_actions = run_actions
30
+
31
+ instance_eval(&@block)
32
+
33
+ on_action if run_actions && respond_to?(:on_action)
34
+ # rescue KDoc::Error => e
35
+ # puts('KDoc::Error in document')
36
+ # puts "key #{unique_key}"
37
+ # # puts "file #{KUtil.data.console_file_hyperlink(resource.file, resource.file)}"
38
+ # puts(e.message)
39
+ # @error = e
40
+ # raise
41
+ rescue StandardError => e
42
+ L.error('Standard error in document')
43
+ puts "key #{unique_key}"
44
+ # puts "file #{KUtil.data.console_file_hyperlink(resource.file, resource.file)}"
45
+ L.error(e.message)
46
+ @error = e
47
+ # L.exception exception2
48
+ raise
49
+ ensure
50
+ @run_actions = nil
51
+ end
52
+
53
+ def unique_key
54
+ @unique_key ||= KDoc.util.build_unique_key(key, type, namespace)
55
+ end
56
+
57
+ def settings(key = nil, **options, &block)
58
+ options ||= {}
59
+
60
+ opts = {}.merge(@options) # Document Options
61
+ .merge(options) # Settings Options
62
+ .merge(parent: self)
63
+
64
+ settings_instance(@data, key, **opts, &block)
65
+ # settings.run_decorators(opts)
66
+ end
67
+
68
+ def table(key = :table, **options, &block)
69
+ # NEED to add support for run_decorators I think
70
+ options.merge(parent: self)
71
+ table_instance(@data, key, **options, &block)
72
+ end
73
+ alias rows table
74
+
75
+ # Sweet add-on would be builders
76
+ # def builder(key, &block)
77
+ # # example
78
+ # KDoc::Builder::Shotstack.new(@data, key, &block)
79
+ # end
80
+
81
+ # def set_data(data)
82
+ # @data = data
83
+ # end
84
+
85
+ def data
86
+ @data.clone
87
+ end
88
+
89
+ def data_struct
90
+ KUtil.data.to_open_struct(data)
91
+ end
92
+ # alias d data_struct
93
+
94
+ def raw_data_struct
95
+ KUtil.data.to_open_struct(raw_data)
96
+ end
97
+
98
+ def get_node_type(node_name)
99
+ node_name = KUtil.data.clean_symbol(node_name)
100
+ node_data = @data[node_name]
101
+
102
+ raise KDoc::Error, "Node not found: #{node_name}" if node_data.nil?
103
+
104
+ if node_data.keys.length == 2 && (node_data.key?('fields') && node_data.key?('rows'))
105
+ :table
106
+ else
107
+ :settings
108
+ end
109
+ end
110
+
111
+ # Removes any meta data eg. "fields" from a table and just returns the raw data
112
+ def raw_data
113
+ # REFACT, what if this is CSV, meaning it is just an array?
114
+ # add specs
115
+ result = data
116
+
117
+ result.each_key do |key|
118
+ # ANTI: get_node_type uses @data while we are using @data.clone here
119
+ data[key] = if get_node_type(key) == :table
120
+ result[key].delete('fields')
121
+ else
122
+ result[key]
123
+ end
124
+ end
125
+
126
+ data
127
+ end
128
+
129
+ # Move this out to the logger function when it has been refactor
130
+ def debug(include_header: false)
131
+ debug_header if include_header
132
+
133
+ # tp dsls.values, :k_key, :k_type, :state, :save_at, :last_at, :data, :last_data, :source, { :file => { :width => 150 } }
134
+ # puts JSON.pretty_generate(data)
135
+ L.o(raw_data_struct)
136
+ end
137
+
138
+ def debug_header
139
+ L.heading self.class.name
140
+ L.kv 'key', key
141
+ L.kv 'type', type
142
+ L.kv 'namespace', namespace
143
+ L.kv 'error', error
144
+
145
+ debug_header_keys
146
+
147
+ L.line
148
+ end
149
+
150
+ def debug_header_keys
151
+ options&.keys&.reject { |k| k == :namespace }&.each do |key|
152
+ L.kv key, options[key]
153
+ end
154
+ end
155
+
156
+ private
157
+
158
+ def initialize_attributes(key = nil, **options)
159
+ @key = key
160
+
161
+ @options = options || {}
162
+ @type = slice_option(:type) || KDoc.opinion.default_document_type
163
+ @namespace = slice_option(:namespace) || ''
164
+ @parent = slice_option(:parent)
165
+
166
+ # Most documents live within a hash, some tabular documents such as CSV will use an []
167
+ @data = slice_option(:default_data) || {}
168
+
169
+ @error = nil
170
+ end
171
+
172
+ def settings_instance(data, key, **options, &block)
173
+ KDoc.opinion.settings_class.new(data, key, **options, &block)
174
+ end
175
+
176
+ def table_instance(data, key, **options, &block)
177
+ KDoc.opinion.table_class.new(data, key, **options, &block)
178
+ end
179
+
180
+ def slice_option(key)
181
+ return nil unless @options.key?(key)
182
+
183
+ result = @options[key]
184
+ @options.delete(key)
185
+ result
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module KDoc
6
+ # This is called fake opinion because I have not figured out
7
+ # how I want to implement this
8
+ class FakeOpinion
9
+ attr_accessor :default_document_type
10
+ attr_accessor :default_settings_key
11
+ attr_accessor :default_table_key
12
+
13
+ attr_accessor :document_class
14
+ attr_accessor :settings_class
15
+ attr_accessor :table_class
16
+
17
+ def initialize
18
+ @default_document_type = :entity
19
+ @default_settings_key = :settings
20
+ @default_table_key = :table
21
+
22
+ @document_class = KDoc::Document
23
+ @table_class = KDoc::Table
24
+ @settings_class = KDoc::Settings
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module KDoc
6
+ # Builds up key/value settings from the block
7
+ # and applies them to a key coded node on the hash
8
+ class Settings
9
+ attr_reader :parent
10
+ attr_reader :key
11
+
12
+ alias kp parent
13
+
14
+ def initialize(data, key = nil, **options, &block)
15
+ initialize_attributes(data, key, **options)
16
+
17
+ # Need a way to find out the line number for errors and report it correctly
18
+ begin
19
+ instance_eval(&block) if block_given?
20
+ # rubocop:disable Style/RescueStandardError
21
+ rescue => e
22
+ # rubocop:enable Style/RescueStandardError
23
+ puts "Invalid code block in settings_dsl: #{@key}"
24
+ puts e.message
25
+ raise
26
+ end
27
+ end
28
+
29
+ def my_data
30
+ @data[@key]
31
+ end
32
+
33
+ # def run_decorators(opts)
34
+ # decorators = KDoc::Decorator.decorate.decorators(opts[:decorators])
35
+
36
+ # return if decorators.empty?
37
+
38
+ # decorators.each do |decorator|
39
+ # decorator.send(:update, my_data) if decorator.respond_to?(:update)
40
+ # decorator.send(:call, my_data) if decorator.respond_to?(:call)
41
+ # end
42
+ # end
43
+
44
+ def respond_to_missing?(name, *_args, &_block)
45
+ # puts 'respond_to_missing?'
46
+ # puts "respond_to_missing: #{name}"
47
+ n = name.to_s
48
+ n = n[0..-2] if n.end_with?('=')
49
+ my_data.key?(n.to_s) || (!@parent.nil? && @parent.respond_to?(name, true)) || super
50
+ end
51
+
52
+ # rubocop:disable Metrics/AbcSize
53
+ def method_missing(name, *args, &_block)
54
+ # puts "method_missing: #{name}"
55
+ # puts "args.length : #{args.length}"
56
+
57
+ if name != :type && !@parent.nil? && @parent.respond_to?(name)
58
+ puts "NAME: #{name}"
59
+ return @parent.public_send(name, *args, &block)
60
+ end
61
+ raise KDoc::Error, 'Multiple setting values is not supported' if args.length > 1
62
+
63
+ add_getter_or_param_method(name)
64
+ add_setter_method(name)
65
+
66
+ send(name, args[0]) if args.length == 1 # name.end_with?('=')
67
+
68
+ super unless self.class.method_defined?(name)
69
+ end
70
+ # rubocop:enable Metrics/AbcSize
71
+
72
+ # Handles Getter method and method with single parameter
73
+ # object.my_name
74
+ # object.my_name('david')
75
+ def add_getter_or_param_method(name)
76
+ # L.progress(1, 'add_getter_or_param_method')
77
+ self.class.class_eval do
78
+ # L.progress(2, 'add_getter_or_param_method')
79
+ name = name.to_s.gsub(/=$/, '')
80
+ # L.progress(3, 'add_getter_or_param_method')
81
+ define_method(name) do |*args|
82
+ # L.progress(4, 'add_getter_or_param_method')
83
+ # L.kv 'add_getter_or_param_method', name
84
+ raise KDoc::Error, 'Multiple setting values is not supported' if args.length > 1
85
+
86
+ if args.length.zero?
87
+ get_value(name)
88
+ else
89
+ send("#{name}=", args[0])
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ # Handles Setter method
96
+ # object.my_name = 'david'
97
+ def add_setter_method(name)
98
+ # L.progress(1, 'add_setter_method')
99
+ self.class.class_eval do
100
+ # L.progress(2, 'add_setter_method')
101
+ name = name.to_s.gsub(/=$/, '')
102
+ # L.progress(3, 'add_setter_method')
103
+ # L.kv 'add_setter_method', name
104
+ define_method("#{name}=") do |value|
105
+ # L.progress(4, 'add_setter_method')
106
+ # L.kv 'value', value
107
+ my_data[name.to_s] = value
108
+ end
109
+ end
110
+ end
111
+
112
+ def get_value(name)
113
+ my_data[name.to_s]
114
+ end
115
+
116
+ def debug
117
+ puts JSON.pretty_generate(my_data)
118
+ end
119
+
120
+ private
121
+
122
+ def initialize_attributes(data, key = nil, **options)
123
+ @data = data
124
+ @key = (key || FakeOpinion.new.default_settings_key).to_s
125
+
126
+ @parent = options[:parent] if !options.nil? && options.key?(:parent)
127
+
128
+ @data[@key] = {}
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KDoc
4
+ # Build rows (aka DataTable) with field definitions and rows of data
5
+ class Table
6
+ attr_reader :parent
7
+ attr_reader :name
8
+
9
+ def initialize(data, name = nil, **options, &block)
10
+ initialize_attributes(data, name, **options)
11
+
12
+ instance_eval(&block) if block_given?
13
+ end
14
+
15
+ def fields(field_definitions)
16
+ fields = @data[@name]['fields']
17
+
18
+ field_definitions.each do |fd|
19
+ fields << if fd.is_a?(String) || fd.is_a?(Symbol)
20
+ field(fd, nil, :string)
21
+ else
22
+ fd
23
+ end
24
+ end
25
+ end
26
+
27
+ # rubocop:disable Metrics/AbcSize
28
+ def row(*args, **named_args)
29
+ fields = @data[@name]['fields']
30
+
31
+ raise "To many values for row, argument #{i}" if args.length > fields.length
32
+
33
+ # Apply column names with defaults
34
+ row = fields.each_with_object({}) do |f, hash|
35
+ hash[f['name']] = f['default']
36
+ end
37
+
38
+ # Override with positional arguments
39
+ args.each_with_index do |arg, i|
40
+ row[fields[i]['name']] = KUtil.data.clean_symbol(arg)
41
+ end
42
+
43
+ # Override with named args
44
+ named_args.each_key do |key|
45
+ row[key.to_s] = named_args[key]
46
+ end
47
+
48
+ @data[@name]['rows'] << row
49
+ row
50
+ end
51
+ # rubocop:enable Metrics/AbcSize
52
+
53
+ # rubocop:disable Naming/AccessorMethodName
54
+ def get_fields
55
+ @data[@name]['fields']
56
+ end
57
+
58
+ def get_rows
59
+ @data[@name]['rows']
60
+ end
61
+ # rubocop:enable Naming/AccessorMethodName
62
+
63
+ def find_row(key, value)
64
+ @data[@name]['rows'].find { |r| r[key] == value }
65
+ end
66
+
67
+ # Field definition
68
+ #
69
+ # @param [String|Symbol] name Name of the field
70
+ # @param args[0] Default value if not specified, nil if not set
71
+ # @param args[1] Type of data, string if not set
72
+ # @param default: Default value (using named params), as above
73
+ # @param type: Type of data (using named params), as above
74
+ # @return [Hash] Field definition
75
+ def field(name, *args, default: nil, type: nil)
76
+ # default value can be found at position 0 or default: tag (see unit test edge cases)
77
+ default_value = if args.length.positive?
78
+ args[0].nil? ? default : args[0]
79
+ else
80
+ default
81
+ end
82
+
83
+ # type can be found at position 1 or type: tag
84
+ type_value = (args.length > 1 ? args[1] : type) || :string
85
+
86
+ {
87
+ 'name' => KUtil.data.clean_symbol(name),
88
+ 'default' => KUtil.data.clean_symbol(default_value),
89
+ 'type' => KUtil.data.clean_symbol(type_value)
90
+ }
91
+ end
92
+ alias f field
93
+
94
+ private
95
+
96
+ def initialize_attributes(data, name = nil, **options)
97
+ @data = data
98
+ @name = (name || FakeOpinion.new.default_table_key.to_s).to_s
99
+
100
+ @parent = options[:parent] if !options.nil? && options.key?(:parent)
101
+
102
+ @data[@name] = { 'fields' => [], 'rows' => [] }
103
+ end
104
+
105
+ def respond_to_missing?(name, *_args, &_block)
106
+ (!@parent.nil? && @parent.respond_to?(name, true)) || super
107
+ end
108
+
109
+ def method_missing(name, *args, &block)
110
+ return super unless @parent.respond_to?(name)
111
+
112
+ @parent.public_send(name, *args, &block)
113
+ end
114
+ end
115
+ end
data/lib/k_doc/util.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KDoc
4
+ # Utility helper methods for KDoc
5
+ class Util
6
+ def build_unique_key(key, type = nil, namespace = nil)
7
+ raise KDoc::Error, 'key is required when generating unique key' if key.nil? || key.empty?
8
+
9
+ type ||= KDoc.opinion.default_document_type
10
+
11
+ namespace.nil? || namespace.empty? ? "#{key}_#{type}" : "#{namespace}_#{key}_#{type}"
12
+ end
13
+ end
14
+ end
data/lib/k_doc/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KDoc
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.4'
5
5
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: k_doc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-30 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: k_log
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: k_util
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.0
13
41
  description: " KDoc provides a document in the form a DSL that contains flexible
14
42
  key/value and tabular data\n"
15
43
  email:
@@ -24,9 +52,12 @@ files:
24
52
  - ".rubocop.yml"
25
53
  - CODE_OF_CONDUCT.md
26
54
  - Gemfile
55
+ - Guardfile
27
56
  - LICENSE.txt
28
57
  - README.md
29
58
  - Rakefile
59
+ - STORIES.md
60
+ - USAGE.md
30
61
  - bin/console
31
62
  - bin/k
32
63
  - bin/kgitsync
@@ -36,6 +67,12 @@ files:
36
67
  - hooks/update-version
37
68
  - k_doc.gemspec
38
69
  - lib/k_doc.rb
70
+ - lib/k_doc/data.rb
71
+ - lib/k_doc/document.rb
72
+ - lib/k_doc/fake_opinion.rb
73
+ - lib/k_doc/settings.rb
74
+ - lib/k_doc/table.rb
75
+ - lib/k_doc/util.rb
39
76
  - lib/k_doc/version.rb
40
77
  homepage: http://appydave.com/gems/k-doc
41
78
  licenses: