k_builder 0.0.28 → 0.0.37
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/lib/k_builder.rb +2 -1
- data/lib/k_builder/base_builder.rb +206 -21
- data/lib/k_builder/base_configuration.rb +22 -2
- data/lib/k_builder/configuration.rb +27 -9
- data/lib/k_builder/data_helper.rb +2 -0
- data/lib/k_builder/layered_folders.rb +104 -0
- data/lib/k_builder/named_folders.rb +100 -0
- data/lib/k_builder/version.rb +1 -1
- metadata +4 -3
- data/lib/k_builder/builder.rb +0 -258
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '094bf462c5d39f6b39aa8df40e75d4623af9c5d1f6594109cb7afb4e9e82bfb2'
|
4
|
+
data.tar.gz: 4dd0400aa1a64e797c56aacc53d3af7ef4cda66c5aca9bbc32f13aeb1604e481
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6196e9716b5e86f7cbdb5dba23252a5e7c477da329e2aa8a6a9989c59b790be10316130a9286fd6c5041c49d85a10282dc206a52ef5c73ce2ddf66601ad3c72
|
7
|
+
data.tar.gz: 301407050730841e77aad746a32bf046c636970346c4cda6f158699a571d125617eef1e15159a6495ba81fff19c125e25578a57f84407958a19c12f73f706dea
|
data/lib/k_builder.rb
CHANGED
@@ -3,9 +3,10 @@
|
|
3
3
|
require 'k_builder/version'
|
4
4
|
require 'k_builder/base_builder'
|
5
5
|
require 'k_builder/base_configuration'
|
6
|
-
require 'k_builder/builder'
|
7
6
|
require 'k_builder/configuration'
|
8
7
|
require 'k_builder/data_helper'
|
8
|
+
require 'k_builder/named_folders'
|
9
|
+
require 'k_builder/layered_folders'
|
9
10
|
|
10
11
|
require 'handlebars/helpers/template'
|
11
12
|
|
@@ -8,7 +8,11 @@ module KBuilder
|
|
8
8
|
# Setter methods (are NOT fluent) can be created as needed
|
9
9
|
# these methods would not be prefixed with the set_
|
10
10
|
class BaseBuilder
|
11
|
-
attr_reader :
|
11
|
+
attr_reader :configuration
|
12
|
+
|
13
|
+
attr_accessor :target_folders
|
14
|
+
|
15
|
+
attr_accessor :template_folders
|
12
16
|
|
13
17
|
# Factory method that provides a builder for a specified structure
|
14
18
|
# runs through a configuration block and then builds the final structure
|
@@ -20,37 +24,23 @@ module KBuilder
|
|
20
24
|
|
21
25
|
# Create and initialize the builder.
|
22
26
|
#
|
23
|
-
# Initialization can be done via any of these three sequential steps.
|
24
|
-
# - Configuration hash
|
25
|
-
# - After new event
|
26
|
-
# - Configuration block (lambda)
|
27
|
-
#
|
28
27
|
# @return [Builder] Returns the builder via fluent interface
|
29
28
|
def self.init(configuration = nil)
|
30
29
|
builder = new(configuration)
|
31
30
|
|
32
|
-
builder.after_new
|
33
|
-
|
34
31
|
yield(builder) if block_given?
|
35
32
|
|
36
33
|
builder
|
37
34
|
end
|
38
35
|
|
39
|
-
# Use after_new to massage hash values that come in via
|
40
|
-
# configuration into more complex values
|
41
|
-
#
|
42
|
-
# Abstract method
|
43
|
-
def after_new; end
|
44
|
-
|
45
36
|
# assigns a builder hash and defines builder methods
|
46
37
|
def initialize(configuration = nil)
|
47
|
-
|
38
|
+
configuration = KBuilder.configuration if configuration.nil?
|
48
39
|
|
49
|
-
|
50
|
-
raise KBuilder::StandardError, 'Unknown configuration object' unless configuration.is_a?(Hash)
|
40
|
+
@configuration = configuration
|
51
41
|
|
52
|
-
|
53
|
-
|
42
|
+
@target_folders = configuration.target_folders.clone
|
43
|
+
@template_folders = configuration.template_folders.clone
|
54
44
|
|
55
45
|
define_builder_setter_methods
|
56
46
|
end
|
@@ -60,15 +50,210 @@ module KBuilder
|
|
60
50
|
#
|
61
51
|
# Abstract method
|
62
52
|
def builder_setter_methods
|
63
|
-
|
53
|
+
[]
|
64
54
|
end
|
65
55
|
|
66
56
|
# @return [Hash/StrongType] Returns data object, can be a hash
|
67
57
|
# or strong typed object that you
|
68
58
|
# have wrapped around the hash
|
69
59
|
def build
|
70
|
-
|
60
|
+
raise NotImplementedError
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_h
|
64
|
+
{
|
65
|
+
target_folders: target_folders.to_h,
|
66
|
+
template_folders: template_folders.to_h
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
# ----------------------------------------------------------------------
|
71
|
+
# Fluent interface
|
72
|
+
# ----------------------------------------------------------------------
|
73
|
+
|
74
|
+
# Internal Actions are considered helpers for the builder, they do
|
75
|
+
# something useful, but they do not tend to implement fluent interfaces.
|
76
|
+
#
|
77
|
+
# They some times do actions, they sometimes return information.
|
78
|
+
#
|
79
|
+
# NOTE: [SRP] - These methods should probably be converted into objects
|
80
|
+
# ----------------------------------------------------------------------
|
81
|
+
|
82
|
+
# Add a file to the target location
|
83
|
+
#
|
84
|
+
# @param [String] file The file name with or without relative path, eg. my_file.json or src/my_file.json
|
85
|
+
# @option opts [String] :content Supply the content that you want to write to the file
|
86
|
+
# @option opts [String] :template Supply the template that you want to write to the file, template will be processed ('nobody') From address
|
87
|
+
# @option opts [String] :content_file File with content, file location is based on where the program is running
|
88
|
+
# @option opts [String] :template_file File with handlebars templated content that will be transformed, file location is based on the configured template_path
|
89
|
+
#
|
90
|
+
# Extra options will be used as data for templates, e.g
|
91
|
+
# @option opts [String] :to Recipient email
|
92
|
+
# @option opts [String] :body The email's body
|
93
|
+
def add_file(file, **opts)
|
94
|
+
full_file = target_file(file)
|
95
|
+
|
96
|
+
FileUtils.mkdir_p(File.dirname(full_file))
|
97
|
+
|
98
|
+
content = process_any_content(**opts)
|
99
|
+
|
100
|
+
File.write(full_file, content)
|
101
|
+
|
102
|
+
# Prettier needs to work with the original file name
|
103
|
+
run_prettier file if opts.key?(:pretty)
|
104
|
+
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
# ----------------------------------------------------------------------
|
109
|
+
# Attributes: Think getter/setter
|
110
|
+
#
|
111
|
+
# The following getter/setters can be referenced both inside and outside
|
112
|
+
# of the fluent builder fluent API. They do not implement the fluent
|
113
|
+
# interface unless prefixed by set_.
|
114
|
+
#
|
115
|
+
# set_: Only setters with the prefix _set are considered fluent.
|
116
|
+
# ----------------------------------------------------------------------
|
117
|
+
|
118
|
+
# Target folders and files
|
119
|
+
# ----------------------------------------------------------------------
|
120
|
+
|
121
|
+
def set_current_folder(folder_key)
|
122
|
+
target_folders.current = folder_key
|
123
|
+
|
124
|
+
self
|
125
|
+
end
|
126
|
+
alias cd set_current_folder
|
127
|
+
|
128
|
+
def current_folder_key
|
129
|
+
target_folders.current
|
130
|
+
end
|
131
|
+
|
132
|
+
# Fluent adder for target folder (KBuilder::NamedFolders)
|
133
|
+
def add_target_folder(folder_key, value)
|
134
|
+
target_folders.add(folder_key, value)
|
135
|
+
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
139
|
+
# Get target folder
|
140
|
+
#
|
141
|
+
# Defaults to current_target_folder
|
142
|
+
def get_target_folder(folder_key = current_folder_key)
|
143
|
+
target_folders.get(folder_key)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Get target file
|
147
|
+
def target_file(file_parts, folder: current_folder_key)
|
148
|
+
File.join(get_target_folder(folder), file_parts)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Template folder & Files
|
152
|
+
# ----------------------------------------------------------------------
|
153
|
+
|
154
|
+
# Fluent adder for template folder (KBuilder::LayeredFolders)
|
155
|
+
def add_template_folder(folder_key, value)
|
156
|
+
template_folders.add(folder_key, value)
|
157
|
+
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
# Get for template folder
|
162
|
+
def get_template_folder(folder_key)
|
163
|
+
template_folders.get(folder_key)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Gets a template_file relative to the template folder, looks first in
|
167
|
+
# local template folder and if not found, looks in global template folder
|
168
|
+
def find_template_file(file_parts)
|
169
|
+
template_folders.find_file(file_parts)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Building content from templates
|
173
|
+
# ----------------------------------------------------------------------
|
174
|
+
|
175
|
+
# Use content from a a selection of content sources
|
176
|
+
#
|
177
|
+
# @option opts [String] :content Just pass through the :content as is.
|
178
|
+
# @option opts [String] :content_file Read content from the :content_file
|
179
|
+
#
|
180
|
+
# Future options
|
181
|
+
# @option opts [String] :content_loren [TODO]Create Loren Ipsum text as a :content_loren count of words
|
182
|
+
# @option opts [String] :content_url Read content from the :content_url
|
183
|
+
#
|
184
|
+
# @return Returns some content
|
185
|
+
def use_content(**opts)
|
186
|
+
return opts[:content] unless opts[:content].nil?
|
187
|
+
|
188
|
+
return unless opts[:content_file]
|
189
|
+
|
190
|
+
cf = opts[:content_file]
|
191
|
+
|
192
|
+
return "Content not found: #{File.expand_path(cf)}" unless File.exist?(cf)
|
193
|
+
|
194
|
+
File.read(cf)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Use template from a a selection of template sources
|
198
|
+
#
|
199
|
+
# @option opts [String] :template Just pass through the :template as is.
|
200
|
+
# @option opts [String] :template_file Read template from the :template_file
|
201
|
+
#
|
202
|
+
# @return Returns some template
|
203
|
+
def use_template(**opts)
|
204
|
+
return opts[:template] unless opts[:template].nil?
|
205
|
+
|
206
|
+
return unless opts[:template_file]
|
207
|
+
|
208
|
+
tf = find_template_file(opts[:template_file])
|
209
|
+
|
210
|
+
return "template not found: #{opts[:template_file]}" if tf.nil?
|
211
|
+
|
212
|
+
File.read(tf)
|
213
|
+
end
|
214
|
+
|
215
|
+
# Process content will take any one of the following
|
216
|
+
# - Raw content
|
217
|
+
# - File based content
|
218
|
+
# - Raw template (translated via handlebars)
|
219
|
+
# - File base template (translated via handlebars)
|
220
|
+
#
|
221
|
+
# Process any of the above inputs to create final content output
|
222
|
+
#
|
223
|
+
# @option opts [String] :content Supply the content that you want to write to the file
|
224
|
+
# @option opts [String] :template Supply the template that you want to write to the file, template will be transformed using handlebars
|
225
|
+
# @option opts [String] :content_file File with content, file location is based on where the program is running
|
226
|
+
# @option opts [String] :template_file File with handlebars templated content that will be transformed, file location is based on the configured template_path
|
227
|
+
def process_any_content(**opts)
|
228
|
+
raw_content = use_content(**opts)
|
229
|
+
|
230
|
+
return raw_content if raw_content
|
231
|
+
|
232
|
+
template_content = use_template(**opts)
|
233
|
+
|
234
|
+
Handlebars::Helpers::Template.render(template_content, opts) unless template_content.nil?
|
235
|
+
end
|
236
|
+
|
237
|
+
def run_prettier(file, log_level: :log)
|
238
|
+
# command = "prettier --check #{file} --write #{file}"
|
239
|
+
command = "npx prettier --loglevel #{log_level} --write #{file}"
|
240
|
+
|
241
|
+
run_command command
|
242
|
+
end
|
243
|
+
|
244
|
+
def run_command(command)
|
245
|
+
# Deep path create if needed
|
246
|
+
target_folder = get_target_folder
|
247
|
+
|
248
|
+
FileUtils.mkdir_p(target_folder)
|
249
|
+
|
250
|
+
build_command = "cd #{target_folder} && #{command}"
|
251
|
+
|
252
|
+
puts build_command
|
253
|
+
|
254
|
+
system(build_command)
|
71
255
|
end
|
256
|
+
alias rc run_command
|
72
257
|
|
73
258
|
# TODO
|
74
259
|
# Support Nesting
|
@@ -16,18 +16,38 @@ module KBuilder
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
# move out into module
|
20
|
+
def to_h
|
20
21
|
hash = {}
|
21
22
|
instance_variables.each do |var|
|
22
23
|
value = instance_variable_get(var)
|
23
24
|
|
24
|
-
value = value
|
25
|
+
value = KBuilder.data.struct_to_hash(value) if complex_type?(value)
|
25
26
|
|
26
27
|
hash[var.to_s.delete('@')] = value
|
27
28
|
end
|
28
29
|
hash
|
29
30
|
end
|
30
31
|
|
32
|
+
# Any basic (aka primitive) type
|
33
|
+
def basic_type?(value)
|
34
|
+
value.is_a?(String) ||
|
35
|
+
value.is_a?(Symbol) ||
|
36
|
+
value.is_a?(FalseClass) ||
|
37
|
+
value.is_a?(TrueClass) ||
|
38
|
+
value.is_a?(Integer) ||
|
39
|
+
value.is_a?(Float)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Anything container that is not a regular class
|
43
|
+
def complex_type?(value)
|
44
|
+
value.is_a?(Array) ||
|
45
|
+
value.is_a?(Hash) ||
|
46
|
+
value.is_a?(Struct) ||
|
47
|
+
value.is_a?(OpenStruct) ||
|
48
|
+
value.respond_to?(:to_h)
|
49
|
+
end
|
50
|
+
|
31
51
|
def kv(name, value)
|
32
52
|
puts "#{name.rjust(30)} : #{value}"
|
33
53
|
end
|
@@ -21,23 +21,41 @@ module KBuilder
|
|
21
21
|
|
22
22
|
# Configuration class
|
23
23
|
class Configuration < BaseConfiguration
|
24
|
-
attr_accessor :
|
25
|
-
attr_accessor :
|
26
|
-
attr_accessor :global_template_folder
|
24
|
+
attr_accessor :target_folders
|
25
|
+
attr_accessor :template_folders
|
27
26
|
|
28
27
|
def initialize
|
29
28
|
super
|
30
|
-
@target_folder = Dir.getwd
|
31
|
-
@template_folder = File.join(Dir.getwd, '.templates')
|
32
|
-
@global_template_folder = nil
|
29
|
+
# @target_folder = Dir.getwd
|
30
|
+
# @template_folder = File.join(Dir.getwd, '.templates')
|
31
|
+
# @global_template_folder = nil
|
32
|
+
@target_folders = NamedFolders.new
|
33
|
+
@template_folders = LayeredFolders.new
|
33
34
|
end
|
34
35
|
|
36
|
+
def initialize_copy(orig)
|
37
|
+
super(orig)
|
38
|
+
|
39
|
+
@target_folders = orig.target_folders.clone
|
40
|
+
@template_folders = orig.template_folders.clone
|
41
|
+
end
|
42
|
+
|
43
|
+
# rubocop:disable Metrics/AbcSize
|
35
44
|
def debug
|
36
45
|
puts '-' * 120
|
37
46
|
puts 'kbuilder base configuration'
|
38
|
-
|
39
|
-
|
40
|
-
|
47
|
+
|
48
|
+
puts 'target_folders'
|
49
|
+
target_folders.folders.each_key do |key|
|
50
|
+
folder = target_folders.folders[key]
|
51
|
+
kv key.to_s, folder
|
52
|
+
end
|
53
|
+
|
54
|
+
puts 'template folders (search order)'
|
55
|
+
template_folders.ordered_folders.each do |folder|
|
56
|
+
puts folder.to_s
|
57
|
+
end
|
41
58
|
end
|
59
|
+
# rubocop:enable Metrics/AbcSize
|
42
60
|
end
|
43
61
|
end
|
@@ -38,6 +38,8 @@ module KBuilder
|
|
38
38
|
return data.map { |v| v.is_a?(OpenStruct) ? struct_to_hash(v) : v }
|
39
39
|
end
|
40
40
|
|
41
|
+
return struct_to_hash(data.to_h) if !data.is_a?(Hash) && data.respond_to?(:to_h)
|
42
|
+
|
41
43
|
data.each_pair.with_object({}) do |(key, value), hash|
|
42
44
|
case value
|
43
45
|
when OpenStruct, Struct, Hash
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KBuilder
|
4
|
+
#
|
5
|
+
# Named folders makes sense for generated/output folders because you may want
|
6
|
+
# more than one type of location to generate output.
|
7
|
+
#
|
8
|
+
# Don't confuse multiple named output folders with sub-paths, when you want to
|
9
|
+
# build up a file name in a child folder, you can do that as part of building
|
10
|
+
# the filename.
|
11
|
+
#
|
12
|
+
# The idea behind named folders is for when you have two or more totally different
|
13
|
+
# outputs that (may live in the a similar location) or live in different locations.
|
14
|
+
|
15
|
+
# Layered folders allow files to be found in any of the searchable folders
|
16
|
+
#
|
17
|
+
# They derive from and thus work just like named folders in that they allow folders
|
18
|
+
# to be stored with easy to remember names/alias's.
|
19
|
+
#
|
20
|
+
# Where they differ is that they are retrieved in preferential search order that is
|
21
|
+
# by default (First In, Last Out) priority aka a Stack (Last In, First Out) or
|
22
|
+
# optionally over ridden via the search_order method
|
23
|
+
#
|
24
|
+
# Layered folders makes sense for use with template files and source data/model
|
25
|
+
# where you can have specific usage files available and if they are not found then
|
26
|
+
# you can use fall-back files in other folders.
|
27
|
+
#
|
28
|
+
# example:
|
29
|
+
# folders = LayeredFolders.new
|
30
|
+
# folders.add(:global , '~/global_templates')
|
31
|
+
# folders.add(:domain , '/my-project/domain_templates')
|
32
|
+
# folders.add(:app , '/my-project/my-app/.templates')
|
33
|
+
#
|
34
|
+
# # Find a file and folder will in folders in this order
|
35
|
+
# # app_templates, then domain_templates and then finally global templates
|
36
|
+
# # ['/my-project/my-app/.templates', '/my-project/domain_templates', '~/global_templates']
|
37
|
+
# #
|
38
|
+
# # Find a file called template1.txt and return its fully-qualified path
|
39
|
+
# folders.find_file('template1.txt')
|
40
|
+
#
|
41
|
+
# # As above, but returns the folder only, file name and sub-paths are ignored
|
42
|
+
# folders.find_file_folder('template1.txt')
|
43
|
+
# folders.find_file_folder('abc/xyz/deep-template.txt')
|
44
|
+
#
|
45
|
+
# # If an additional folder is added, say in child configuration that is designed
|
46
|
+
# # to override some of the global templates, then you can run a search_order
|
47
|
+
# # method to re-order the templates
|
48
|
+
#
|
49
|
+
# folders.add(:global_shim , '~/global_templates_shim')
|
50
|
+
# folders.search_order(:app, :domain, :global_shim, :global)
|
51
|
+
#
|
52
|
+
# class Builder < KBuilder::BaseBuilder
|
53
|
+
class LayeredFolders < KBuilder::NamedFolders
|
54
|
+
attr_reader :ordered_keys
|
55
|
+
attr_reader :ordered_folders
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
super()
|
59
|
+
|
60
|
+
@ordered_keys = []
|
61
|
+
@ordered_folders = []
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize_copy(orig)
|
65
|
+
super(orig)
|
66
|
+
|
67
|
+
@ordered_keys = orig.ordered_keys.clone
|
68
|
+
@ordered_folders = orig.ordered_folders.clone
|
69
|
+
end
|
70
|
+
|
71
|
+
def add(folder_key, folder)
|
72
|
+
folder = super(folder_key, folder)
|
73
|
+
|
74
|
+
ordered_keys.prepend(folder_key)
|
75
|
+
ordered_folders.prepend(folder)
|
76
|
+
|
77
|
+
folder
|
78
|
+
end
|
79
|
+
|
80
|
+
# File name or array of sub-paths plus file
|
81
|
+
#
|
82
|
+
# Return the folder that a file is found in
|
83
|
+
def find_file(file_parts)
|
84
|
+
folder = find_file_folder(file_parts)
|
85
|
+
folder.nil? ? nil : File.join(folder, file_parts)
|
86
|
+
end
|
87
|
+
|
88
|
+
# File name or array of sub-paths plus file
|
89
|
+
#
|
90
|
+
# Return the folder that a file is found in
|
91
|
+
def find_file_folder(file_parts)
|
92
|
+
ordered_folders.find { |folder| File.exist?(File.join(folder, file_parts)) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_h
|
96
|
+
{
|
97
|
+
ordered: {
|
98
|
+
keys: ordered_keys,
|
99
|
+
folders: ordered_folders
|
100
|
+
}
|
101
|
+
}.merge(@folders)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KBuilder
|
4
|
+
# Named folders allow folders to be stored with easy to remember names/alias's
|
5
|
+
# Secondarily, you can also build up file names based on these named folders.
|
6
|
+
#
|
7
|
+
# Named folders makes sense for generated/output folders because you may want
|
8
|
+
# more than one type of location to generate output.
|
9
|
+
#
|
10
|
+
# Don't confuse multiple named output folders with sub-paths, when you want to
|
11
|
+
# build up a file name in a child folder, you can do that as part of building
|
12
|
+
# the filename.
|
13
|
+
#
|
14
|
+
# The idea behind named folders is for when you have two or more totally different
|
15
|
+
# outputs that (may live in the a similar location) or live in different locations.
|
16
|
+
# Samples:
|
17
|
+
# name: :code - generating source code into a project
|
18
|
+
# name: :slide - generating slide deck into a documentation folder
|
19
|
+
# name: :webpack - folder where you might generate webpack files, e.g. webpack.config.*.json
|
20
|
+
#
|
21
|
+
# example:
|
22
|
+
# folders = NamedFolders.new
|
23
|
+
# folders.add(:csharp , '~/dev/csharp/cool-project')
|
24
|
+
# folders.add(:package_json , :csharp)
|
25
|
+
# folders.add(:webpack , folders.join(:csharp, 'config'))
|
26
|
+
# folders.add(:builder , folders.join(:csharp, 'builder'))
|
27
|
+
# folders.add(:slides , '~/doc/csharp/cool-project')
|
28
|
+
#
|
29
|
+
# puts folders.get(:builder)
|
30
|
+
#
|
31
|
+
# puts folders.get_filename(:csharp, 'Program.cs')
|
32
|
+
# puts folders.get_filename(:csharp, 'Models/Order.cs')
|
33
|
+
# puts folders.get_filename(:csharp, 'Models', 'Order.cs')
|
34
|
+
#
|
35
|
+
# Do I need to support :default?
|
36
|
+
class NamedFolders
|
37
|
+
attr_reader :folders
|
38
|
+
|
39
|
+
attr_reader :current
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@folders = {}
|
43
|
+
@current = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize_copy(orig)
|
47
|
+
super(orig)
|
48
|
+
|
49
|
+
@folders = orig.folders.clone
|
50
|
+
end
|
51
|
+
|
52
|
+
def current=(folder_key)
|
53
|
+
guard_folder_key(folder_key)
|
54
|
+
@current = folder_key
|
55
|
+
end
|
56
|
+
|
57
|
+
def add(folder_key, folder)
|
58
|
+
# get a predefined folder by symbol
|
59
|
+
if folder.is_a?(Symbol)
|
60
|
+
folder = get(folder)
|
61
|
+
elsif folder.start_with?('~')
|
62
|
+
folder = File.expand_path(folder)
|
63
|
+
end
|
64
|
+
|
65
|
+
@current = folder_key if @current.nil?
|
66
|
+
folders[folder_key] = folder
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get a folder
|
70
|
+
def get(folder_key)
|
71
|
+
guard_folder_key(folder_key)
|
72
|
+
folders[folder_key]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Join the lookup folder key with the subpath folder parts (optionally + filename) and return the folder or filename
|
76
|
+
#
|
77
|
+
# Return fully qualified filename
|
78
|
+
def join(folder_key, *file_folder_parts)
|
79
|
+
folder = get(folder_key)
|
80
|
+
|
81
|
+
File.join(folder, file_folder_parts)
|
82
|
+
end
|
83
|
+
# Get a file name using the lookup folder key and the file name or array of sub-paths plus filename
|
84
|
+
alias get_filename join
|
85
|
+
|
86
|
+
def folder_keys
|
87
|
+
@folders.keys
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_h
|
91
|
+
@folders
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def guard_folder_key(folder_key)
|
97
|
+
raise KBuilder::Error, "Folder not found, this folder key not found: #{folder_key}" unless folders.key?(folder_key)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/k_builder/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: k_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.37
|
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-
|
11
|
+
date: 2021-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: handlebars-helpers
|
@@ -55,9 +55,10 @@ files:
|
|
55
55
|
- lib/k_builder.rb
|
56
56
|
- lib/k_builder/base_builder.rb
|
57
57
|
- lib/k_builder/base_configuration.rb
|
58
|
-
- lib/k_builder/builder.rb
|
59
58
|
- lib/k_builder/configuration.rb
|
60
59
|
- lib/k_builder/data_helper.rb
|
60
|
+
- lib/k_builder/layered_folders.rb
|
61
|
+
- lib/k_builder/named_folders.rb
|
61
62
|
- lib/k_builder/version.rb
|
62
63
|
- usage/_out1.png
|
63
64
|
- usage/_out2.png
|
data/lib/k_builder/builder.rb
DELETED
@@ -1,258 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module KBuilder
|
4
|
-
# Base builder defines builder methods, build method and configuration
|
5
|
-
class Builder < KBuilder::BaseBuilder
|
6
|
-
# builder_setter_methods = %w[].freeze
|
7
|
-
# target_folder
|
8
|
-
# template_folder
|
9
|
-
# global_template_folder
|
10
|
-
|
11
|
-
def initialize(configuration = nil)
|
12
|
-
configuration = KBuilder.configuration.to_hash if configuration.nil?
|
13
|
-
|
14
|
-
super(configuration)
|
15
|
-
end
|
16
|
-
|
17
|
-
# rubocop:disable Metrics/AbcSize
|
18
|
-
def after_new
|
19
|
-
# ensure that any configured folders are expanded
|
20
|
-
self.target_folder = hash['target_folder'] unless hash['target_folder'].nil?
|
21
|
-
self.template_folder = hash['template_folder'] unless hash['template_folder'].nil?
|
22
|
-
self.global_template_folder = hash['global_template_folder'] unless hash['global_template_folder'].nil?
|
23
|
-
end
|
24
|
-
# rubocop:enable Metrics/AbcSize
|
25
|
-
|
26
|
-
# Return an array of symbols to represent the fluent setter methods in this builder.
|
27
|
-
def builder_setter_methods
|
28
|
-
# Currently I have manually created my settings because I needed custom
|
29
|
-
# logic in the settings to handle path expansion
|
30
|
-
[]
|
31
|
-
end
|
32
|
-
|
33
|
-
# def build
|
34
|
-
# # SomeDryStruct.new(hash)
|
35
|
-
# end
|
36
|
-
|
37
|
-
# ----------------------------------------------------------------------
|
38
|
-
# Fluent interface
|
39
|
-
# ----------------------------------------------------------------------
|
40
|
-
|
41
|
-
# Add a file to the target location
|
42
|
-
#
|
43
|
-
# @param [String] file The file name with or without relative path, eg. my_file.json or src/my_file.json
|
44
|
-
# @option opts [String] :content Supply the content that you want to write to the file
|
45
|
-
# @option opts [String] :template Supply the template that you want to write to the file, template will be processed ('nobody') From address
|
46
|
-
# @option opts [String] :content_file File with content, file location is based on where the program is running
|
47
|
-
# @option opts [String] :template_file File with handlebars templated content that will be transformed, file location is based on the configured template_path
|
48
|
-
#
|
49
|
-
# Extra options will be used as data for templates, e.g
|
50
|
-
# @option opts [String] :to Recipient email
|
51
|
-
# @option opts [String] :body The email's body
|
52
|
-
def add_file(file, **opts)
|
53
|
-
full_file = target_file(file)
|
54
|
-
|
55
|
-
FileUtils.mkdir_p(File.dirname(full_file))
|
56
|
-
|
57
|
-
content = process_any_content(**opts)
|
58
|
-
|
59
|
-
File.write(full_file, content)
|
60
|
-
|
61
|
-
# Prettier needs to work with the original file name
|
62
|
-
run_prettier file if opts.key?(:pretty)
|
63
|
-
|
64
|
-
self
|
65
|
-
end
|
66
|
-
|
67
|
-
# ----------------------------------------------------------------------
|
68
|
-
# Attributes: Think getter/setter
|
69
|
-
#
|
70
|
-
# The following getter/setters can be referenced both inside and outside
|
71
|
-
# of the fluent builder fluent API. They do not implement the fluent
|
72
|
-
# interface unless prefixed by set_.
|
73
|
-
#
|
74
|
-
# set_: Only setters with the prefix _set are considered fluent.
|
75
|
-
# ----------------------------------------------------------------------
|
76
|
-
|
77
|
-
# Target folder
|
78
|
-
# ----------------------------------------------------------------------
|
79
|
-
|
80
|
-
# Fluent setter for target folder
|
81
|
-
def set_target_folder(value)
|
82
|
-
self.target_folder = value
|
83
|
-
|
84
|
-
self
|
85
|
-
end
|
86
|
-
|
87
|
-
# Setter for target folder
|
88
|
-
def target_folder=(value)
|
89
|
-
hash['target_folder'] = File.expand_path(value)
|
90
|
-
end
|
91
|
-
|
92
|
-
# Getter for target folder
|
93
|
-
def target_folder
|
94
|
-
hash['target_folder']
|
95
|
-
end
|
96
|
-
|
97
|
-
# Template folder
|
98
|
-
# ----------------------------------------------------------------------
|
99
|
-
|
100
|
-
# Fluent setter for template folder
|
101
|
-
def set_template_folder(value)
|
102
|
-
self.template_folder = value
|
103
|
-
|
104
|
-
self
|
105
|
-
end
|
106
|
-
|
107
|
-
# Setter for template folder
|
108
|
-
# Refactor: Make Private
|
109
|
-
def template_folder=(value)
|
110
|
-
hash['template_folder'] = File.expand_path(value)
|
111
|
-
end
|
112
|
-
|
113
|
-
# Getter for template folder
|
114
|
-
# Refactor: generate
|
115
|
-
def template_folder
|
116
|
-
hash['template_folder']
|
117
|
-
end
|
118
|
-
|
119
|
-
# Global Target folder
|
120
|
-
# ----------------------------------------------------------------------
|
121
|
-
|
122
|
-
# Fluent setter for global template folder
|
123
|
-
def set_global_template_folder(value)
|
124
|
-
self.global_template_folder = value
|
125
|
-
|
126
|
-
self
|
127
|
-
end
|
128
|
-
|
129
|
-
# Setter for global template folder
|
130
|
-
# Refactor: Make Private
|
131
|
-
def global_template_folder=(value)
|
132
|
-
hash['global_template_folder'] = File.expand_path(value)
|
133
|
-
end
|
134
|
-
|
135
|
-
# Setter for global template folder
|
136
|
-
# Refactor: generate
|
137
|
-
def global_template_folder
|
138
|
-
hash['global_template_folder']
|
139
|
-
end
|
140
|
-
|
141
|
-
# Internal Actions are considered helpers for the builder, they do
|
142
|
-
# something useful, but they do not tend to implement fluent interfaces.
|
143
|
-
#
|
144
|
-
# They some times do actions, they sometimes return information.
|
145
|
-
#
|
146
|
-
# NOTE: [SRP] - These methods should probably be converted into objects
|
147
|
-
# ----------------------------------------------------------------------
|
148
|
-
|
149
|
-
# Gets a target_file relative to target folder
|
150
|
-
def target_file(file)
|
151
|
-
File.join(target_folder, file)
|
152
|
-
end
|
153
|
-
|
154
|
-
# Gets a template_file relative to the template folder
|
155
|
-
def template_file(file)
|
156
|
-
File.join(template_folder, file)
|
157
|
-
end
|
158
|
-
|
159
|
-
# Gets a global_template_file relative to the global template folder
|
160
|
-
def global_template_file(file)
|
161
|
-
File.join(global_template_folder, file)
|
162
|
-
end
|
163
|
-
|
164
|
-
# Gets a template_file relative to the template folder, looks first in
|
165
|
-
# local template folder and if not found, looks in global template folder
|
166
|
-
def find_template_file(file)
|
167
|
-
full_file = template_file(file)
|
168
|
-
return full_file if File.exist?(full_file)
|
169
|
-
|
170
|
-
full_file = global_template_file(file)
|
171
|
-
return full_file if File.exist?(full_file)
|
172
|
-
|
173
|
-
# File not found
|
174
|
-
nil
|
175
|
-
end
|
176
|
-
|
177
|
-
# Use content from a a selection of content sources
|
178
|
-
#
|
179
|
-
# @option opts [String] :content Just pass through the :content as is.
|
180
|
-
# @option opts [String] :content_file Read content from the :content_file
|
181
|
-
#
|
182
|
-
# Future options
|
183
|
-
# @option opts [String] :content_loren [TODO]Create Loren Ipsum text as a :content_loren count of words
|
184
|
-
# @option opts [String] :content_url Read content from the :content_url
|
185
|
-
#
|
186
|
-
# @return Returns some content
|
187
|
-
def use_content(**opts)
|
188
|
-
return opts[:content] unless opts[:content].nil?
|
189
|
-
|
190
|
-
return unless opts[:content_file]
|
191
|
-
|
192
|
-
cf = opts[:content_file]
|
193
|
-
|
194
|
-
return "Content not found: #{File.expand_path(cf)}" unless File.exist?(cf)
|
195
|
-
|
196
|
-
File.read(cf)
|
197
|
-
end
|
198
|
-
|
199
|
-
# Use template from a a selection of template sources
|
200
|
-
#
|
201
|
-
# @option opts [String] :template Just pass through the :template as is.
|
202
|
-
# @option opts [String] :template_file Read template from the :template_file
|
203
|
-
#
|
204
|
-
# @return Returns some template
|
205
|
-
def use_template(**opts)
|
206
|
-
return opts[:template] unless opts[:template].nil?
|
207
|
-
|
208
|
-
return unless opts[:template_file]
|
209
|
-
|
210
|
-
tf = find_template_file(opts[:template_file])
|
211
|
-
|
212
|
-
return "template not found: #{opts[:template_file]}" if tf.nil?
|
213
|
-
|
214
|
-
File.read(tf)
|
215
|
-
end
|
216
|
-
|
217
|
-
# Process content will take any one of the following
|
218
|
-
# - Raw content
|
219
|
-
# - File based content
|
220
|
-
# - Raw template (translated via handlebars)
|
221
|
-
# - File base template (translated via handlebars)
|
222
|
-
#
|
223
|
-
# Process any of the above inputs to create final content output
|
224
|
-
#
|
225
|
-
# @option opts [String] :content Supply the content that you want to write to the file
|
226
|
-
# @option opts [String] :template Supply the template that you want to write to the file, template will be transformed using handlebars
|
227
|
-
# @option opts [String] :content_file File with content, file location is based on where the program is running
|
228
|
-
# @option opts [String] :template_file File with handlebars templated content that will be transformed, file location is based on the configured template_path
|
229
|
-
def process_any_content(**opts)
|
230
|
-
raw_content = use_content(**opts)
|
231
|
-
|
232
|
-
return raw_content if raw_content
|
233
|
-
|
234
|
-
template_content = use_template(**opts)
|
235
|
-
|
236
|
-
Handlebars::Helpers::Template.render(template_content, opts) unless template_content.nil?
|
237
|
-
end
|
238
|
-
|
239
|
-
def run_prettier(file, log_level: :log)
|
240
|
-
# command = "prettier --check #{file} --write #{file}"
|
241
|
-
command = "npx prettier --loglevel #{log_level} --write #{file}"
|
242
|
-
|
243
|
-
run_command command
|
244
|
-
end
|
245
|
-
|
246
|
-
def run_command(command)
|
247
|
-
# Deep path create if needed
|
248
|
-
FileUtils.mkdir_p(target_folder)
|
249
|
-
|
250
|
-
build_command = "cd #{target_folder} && #{command}"
|
251
|
-
|
252
|
-
puts build_command
|
253
|
-
|
254
|
-
system(build_command)
|
255
|
-
end
|
256
|
-
alias rc run_command
|
257
|
-
end
|
258
|
-
end
|