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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2dcd63316f0cc08692e83ef120cd5a9b940a4e3b73439cda7e6a298be420a05f
4
- data.tar.gz: '08e1adbd07386448c9c60bbdacbc069257660e216d8fd0aea6417bae94ee5342'
3
+ metadata.gz: '094bf462c5d39f6b39aa8df40e75d4623af9c5d1f6594109cb7afb4e9e82bfb2'
4
+ data.tar.gz: 4dd0400aa1a64e797c56aacc53d3af7ef4cda66c5aca9bbc32f13aeb1604e481
5
5
  SHA512:
6
- metadata.gz: fa441f9ed2e140c89cad9bf3e0246b82489572e3f3843e053e681310dfb86a7b92648bec69f2578b3cc37b4c74fd258e9b6f97829e727d12f80a49284c2a8e92
7
- data.tar.gz: 20d753e90550f3d28ab66f82c756e8f22fca1056c4b7af0bdc2ecc5105e89c28b33392baf083648d6dbffdacd800bad0ef9c07f95112fa67713e3a16d61c74e8
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 :hash
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
- @hash = {}
38
+ configuration = KBuilder.configuration if configuration.nil?
48
39
 
49
- unless configuration.nil?
50
- raise KBuilder::StandardError, 'Unknown configuration object' unless configuration.is_a?(Hash)
40
+ @configuration = configuration
51
41
 
52
- hash.merge!(configuration)
53
- end
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
- raise NotImplementedError
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
- hash
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
- def to_hash
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.to_hash if value.is_a?(KBuilder::BaseConfiguration)
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 :target_folder
25
- attr_accessor :template_folder
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
- kv 'target_folder' , target_folder
39
- kv 'template_folder' , template_folder
40
- kv 'global_template_folder', global_template_folder
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KBuilder
4
- VERSION = '0.0.28'
4
+ VERSION = '0.0.37'
5
5
  end
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.28
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-15 00:00:00.000000000 Z
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
@@ -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