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 +4 -4
- data/.rubocop.yml +3 -0
- data/Guardfile +30 -0
- data/README.md +10 -3
- data/STORIES.md +44 -0
- data/USAGE.md +19 -0
- data/k_doc.gemspec +2 -0
- data/lib/k_doc.rb +43 -1
- data/lib/k_doc/data.rb +258 -0
- data/lib/k_doc/document.rb +188 -0
- data/lib/k_doc/fake_opinion.rb +27 -0
- data/lib/k_doc/settings.rb +131 -0
- data/lib/k_doc/table.rb +115 -0
- data/lib/k_doc/util.rb +14 -0
- data/lib/k_doc/version.rb +1 -1
- metadata +40 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3ade2c96c7dd68a9b948f680c63a3a3f28d79f48a3808df328435054e32048f
|
4
|
+
data.tar.gz: f932c466c175cd9258220b370ea040982e2fd57be560fd816c8a60818d4344c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f18c5daebd800c3e3e33ce5c8ec882833cc64b97c7d8b415c6078abed1c7fce76a6bb59f53afe51511035e77e198fdd1e106cf746dcff6fa7a96a3d0af88128
|
7
|
+
data.tar.gz: 36ab77e3f217d639bc02f911b23674322ad0dd2c2e1aed0042f57195fda0b6b8f95e0119758e0c85f0bddb485b0ea77d73d2543b6c515b315bb5c5d95171ab77
|
data/.rubocop.yml
CHANGED
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
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
|
-
|
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
|
data/lib/k_doc/table.rb
ADDED
@@ -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
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.
|
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-
|
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:
|