Class: KBuilder::BaseBuilder

Inherits:
Object
  • Object
show all
Includes:
KLog::Logging
Defined in:
lib/k_builder/base_builder.rb

Overview

process_any_content(content_gist: ‘gist.github.com/klueless-io/8d4b6d199dbe4a5d40807a47fff8ed1c’) process_any_content(template_gist: ‘gist.github.com/klueless-io/8d4b6d199dbe4a5d40807a47fff8ed1c’, name: ‘sean’)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(configuration = nil) ⇒ BaseBuilder

assigns a builder hash and defines builder methods



56
57
58
59
60
61
62
63
# File 'lib/k_builder/base_builder.rb', line 56

def initialize(configuration = nil)
  configuration = KConfig.configuration if configuration.nil?

  @configuration = configuration

  @target_folders = configuration.target_folders.clone
  @template_folders = configuration.template_folders.clone
end

Instance Attribute Details

#configurationObject (readonly)

Returns the value of attribute configuration.



26
27
28
# File 'lib/k_builder/base_builder.rb', line 26

def configuration
  @configuration
end

#last_output_fileObject

Returns the value of attribute last_output_file.



31
32
33
# File 'lib/k_builder/base_builder.rb', line 31

def last_output_file
  @last_output_file
end

#last_output_folderObject

Returns the value of attribute last_output_folder.



32
33
34
# File 'lib/k_builder/base_builder.rb', line 32

def last_output_folder
  @last_output_folder
end

#last_template_fileObject

attr_accessor :last_template



34
35
36
# File 'lib/k_builder/base_builder.rb', line 34

def last_template_file
  @last_template_file
end

#target_foldersObject

Returns the value of attribute target_folders.



28
29
30
# File 'lib/k_builder/base_builder.rb', line 28

def target_folders
  @target_folders
end

#template_foldersObject

Returns the value of attribute template_folders.



29
30
31
# File 'lib/k_builder/base_builder.rb', line 29

def template_folders
  @template_folders
end

Class Method Details

.buildtype=Object

Factory method that provides a builder for a specified structure runs through a configuration block and then builds the final structure

Returns:

  • (type=Object)

    data structure



40
41
42
# File 'lib/k_builder/base_builder.rb', line 40

def self.build
  init.build
end

.init(configuration = nil) {|builder| ... } ⇒ Builder

Create and initialize the builder.

Yields:

  • (builder)

Returns:

  • (Builder)

    Returns the builder via fluent interface



47
48
49
50
51
52
53
# File 'lib/k_builder/base_builder.rb', line 47

def self.init(configuration = nil)
  builder = new(configuration)

  yield(builder) if block_given?

  builder
end

Instance Method Details

#add_clipboard(**opts) ⇒ Object Also known as: clipboard_copy

Add content to the clipboard

Extra options will be used as data for templates, e.g

Parameters:

  • opts (Hash)

    a customizable set of options

Options Hash (**opts):

  • :content (String)

    Supply the content that you want to write to the file

  • :template (String)

    Supply the template that you want to write to the file, template will be processed (‘nobody’) From address

  • :content_file (String)

    File with content, file location is based on where the program is running

  • :template_file (String)

    File with handlebars templated content that will be transformed, file location is based on the configured template_path

  • :to (String)

    Recipient email

  • :body (String)

    The email’s body



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/k_builder/base_builder.rb', line 252

def add_clipboard(**opts)
  # move to command
  content = process_any_content(**opts)

  begin
    IO.popen('pbcopy', 'w') { |f| f << content }

    open_file(last_template_file) if opts.key?(:open_template)
  rescue Errno::ENOENT => e
    if e.message == 'No such file or directory - pbcopy'
      # May want to use this GEM in the future
      # https://github.com/janlelis/clipboard
      puts 'Clipboard paste is currently only supported on MAC'
    end
  end

  self
end

#add_clipboard_action(**opts) ⇒ Object



272
273
274
275
276
277
278
# File 'lib/k_builder/base_builder.rb', line 272

def add_clipboard_action(**opts)
  {
    action: :add_clipboard,
    played: false,
    opts: opts
  }
end

#add_file(file, **opts) ⇒ Object Also known as: touch

rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/k_builder/base_builder.rb', line 134

def add_file(file, **opts)
  # move to command
  full_file = target_file(file, **opts) # opts.key?(:folder_key) || opts.key?(:folder) ? target_file(file, folder: opts[:folder], folder_key: opts[:folder_key]) : target_file(file)

  # Need logging options that can log these internal details
  mkdir_p(File.dirname(full_file))

  content = process_any_content(**opts)

  file_write(full_file, content, on_exist: opts[:on_exist])

  # Prettier needs to work with the original file name
  run_prettier file                   if opts.key?(:pretty)
  # TODO: Add test
  run_cop(full_file, fix_safe: true)  if opts.key?(:cop) || opts.key?(:ruby_cop)
  # TODO: Add test
  run_command(file)                   if opts.key?(:run)

  # Need support for rubocop -a
  open_file(last_output_file)         if opts.key?(:open)
  open_file(last_template_file)       if opts.key?(:open_template)
  browse_file(last_output_file)       if opts.key?(:browse)
  pause(opts[:pause])                 if opts[:pause]

  self
end

#add_file_action(file, **opts) ⇒ Object

Add a file to the target location

Extra options will be used as data for templates, e.g

Parameters:

  • file (String)

    The file name with or without relative path, eg. my_file.json or src/my_file.json

  • opts (Hash)

    a customizable set of options

Options Hash (**opts):

  • :content (String)

    Supply the content that you want to write to the file

  • :template (String)

    Supply the template that you want to write to the file, template will be processed (‘nobody’) From address

  • :content_file (String)

    File with content, file location is based on where the program is running

  • :template_file (String)

    File with handlebars templated content that will be transformed, file location is based on the configured template_path

  • :to (String)

    Recipient email

  • :body (String)

    The email’s body



124
125
126
127
128
129
130
131
# File 'lib/k_builder/base_builder.rb', line 124

def add_file_action(file, **opts)
  {
    action: :add_file,
    played: false,
    file: file,
    opts: opts
  }
end

#add_target_folder(folder_key, value) ⇒ Object

Fluent adder for target folder (KBuilder::NamedFolders)



387
388
389
390
391
# File 'lib/k_builder/base_builder.rb', line 387

def add_target_folder(folder_key, value)
  target_folders.add(folder_key, value)

  self
end

#add_template_folder(folder_key, value) ⇒ Object

Fluent adder for template folder (KBuilder::LayeredFolders)



439
440
441
442
443
# File 'lib/k_builder/base_builder.rb', line 439

def add_template_folder(folder_key, value)
  template_folders.add(folder_key, value)

  self
end

#browse(*file_parts, folder_key: current_folder_key, file: nil) ⇒ Object



307
308
309
310
311
312
313
314
# File 'lib/k_builder/base_builder.rb', line 307

def browse(*file_parts, folder_key: current_folder_key, file: nil)
  # move to command
  file = target_file(*file_parts, folder_key: folder_key) if file.nil?

  rc "open -a \"Google Chrome\" #{file}"

  self
end

#browse_action(*file_parts, folder_key: current_folder_key, file: nil) ⇒ Object



298
299
300
301
302
303
304
305
# File 'lib/k_builder/base_builder.rb', line 298

def browse_action(*file_parts, folder_key: current_folder_key, file: nil)
  {
    action: :browse,
    played: false,
    file_parts: file_parts,
    opts: { folder_key: folder_key, file: file }
  }
end

#browse_file(file) ⇒ Object



341
342
343
344
345
346
347
348
349
350
# File 'lib/k_builder/base_builder.rb', line 341

def browse_file(file)
  if file.nil?
    log.warn('browse_file will not browse when file is nil')
    return self
  end

  browse(file: file)

  self
end

#buildHash/StrongType

Returns data object, can be a hash or strong typed object that you have wrapped around the hash

Returns:

  • (Hash/StrongType)

    Returns data object, can be a hash or strong typed object that you have wrapped around the hash

Raises:

  • (NotImplementedError)


68
69
70
# File 'lib/k_builder/base_builder.rb', line 68

def build
  raise NotImplementedError
end

#current_folder_keyObject



393
394
395
# File 'lib/k_builder/base_builder.rb', line 393

def current_folder_key
  target_folders.current
end

#debugObject

rubocop:disable Metrics/AbcSize



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/k_builder/base_builder.rb', line 80

def debug
  log.subheading 'kbuilder'

  log.kv 'current folder key' , current_folder_key
  log.kv 'current folder'     , target_folder
  target_folders.debug(title: 'target_folders')

  log.info ''

  template_folders.debug(title: 'template folders (search order)')

  log.info ''
  log.kv 'last output file'     , last_output_file
  log.kv 'last output folder'   , last_output_folder
  # log.kv 'last template'        , last_template
  log.kv 'last template file'   , last_template_file

  ''
end

#delete_file(file, **opts) ⇒ Object



210
211
212
213
214
215
216
# File 'lib/k_builder/base_builder.rb', line 210

def delete_file(file, **opts)
  full_file = target_file(file, **opts) # = opts.key?(:folder_key) ? target_file(file, folder: opts[:folder_key]) : target_file(file)

  FileUtils.rm_rf(full_file)

  self
end

#delete_file_action(file, **opts) ⇒ Object

it is expected that you would not supply any options, just a file name



201
202
203
204
205
206
207
208
# File 'lib/k_builder/base_builder.rb', line 201

def delete_file_action(file, **opts)
  {
    action: :delete_file,
    played: false,
    file: file,
    opts: opts
  }
end

#file_exist?(file, **opts) ⇒ Boolean

Returns:

  • (Boolean)


218
219
220
221
222
223
# File 'lib/k_builder/base_builder.rb', line 218

def file_exist?(file, **opts)
  # full_file = opts.key?(:folder_key) ? target_file(file, folder_key: opts[:folder_key]) : target_file(file)
  full_file = target_file(file, **opts)

  File.exist?(full_file)
end

#file_write(file, content, on_exist: :skip) ⇒ Object



603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
# File 'lib/k_builder/base_builder.rb', line 603

def file_write(file, content, on_exist: :skip)
  self.last_output_file = file # if file not found, we still want to record this as the last_output_file

  not_found = !File.exist?(file)

  if not_found
    File.write(file, content)
    return
  end

  return if i[skip ignore].include?(on_exist)

  if i[overwrite write].include?(on_exist)
    File.write(file, content)
    return
  end

  return unless on_exist == :compare

  vscompare(file, content)
end

#find_template_file(file_parts) ⇒ Object

Gets a template_file relative to the template folder, looks first in local template folder and if not found, looks in global template folder



452
453
454
455
# File 'lib/k_builder/base_builder.rb', line 452

def find_template_file(file_parts)
  self.last_template_file = template_folders.find_file(file_parts)
  last_template_file
end

#get_template_folder(folder_key) ⇒ Object

Get for template folder



446
447
448
# File 'lib/k_builder/base_builder.rb', line 446

def get_template_folder(folder_key)
  template_folders.get(folder_key)
end

#make_folder(folder_key = nil, sub_path: nil) ⇒ Object

self end



232
233
234
235
236
237
238
239
240
# File 'lib/k_builder/base_builder.rb', line 232

def make_folder(folder_key = nil, sub_path: nil)
  folder_key  = current_folder_key if folder_key.nil?
  folder      = target_folder(folder_key)
  folder      = File.join(folder, sub_path) unless sub_path.nil?

  mkdir_p(folder)

  self
end

#mkdir_p(folder) ⇒ Object



640
641
642
# File 'lib/k_builder/base_builder.rb', line 640

def mkdir_p(folder)
  @last_output_folder = FileUtils.mkdir_p(folder).first
end

#openObject Also known as: o



316
317
318
319
320
# File 'lib/k_builder/base_builder.rb', line 316

def open
  open_file(last_output_file)

  self
end

#open_file(file) ⇒ Object



330
331
332
333
334
335
336
337
338
339
# File 'lib/k_builder/base_builder.rb', line 330

def open_file(file)
  if file.nil?
    log.warn('open_file will not open when file is nil')
    return self
  end

  vscode(file: file)

  self
end

#open_templateObject Also known as: ot



323
324
325
326
327
# File 'lib/k_builder/base_builder.rb', line 323

def open_template
  open_file(last_template_file)

  self
end

#pause(seconds = 1) ⇒ Object



352
353
354
355
356
# File 'lib/k_builder/base_builder.rb', line 352

def pause(seconds = 1)
  sleep(seconds)

  self
end

#play_action(action) ⇒ Object



168
169
170
171
# File 'lib/k_builder/base_builder.rb', line 168

def play_action(action)
  run_action(action)
  action[:played] = true
end

#play_actions(actions) ⇒ Object

rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



162
163
164
165
166
# File 'lib/k_builder/base_builder.rb', line 162

def play_actions(actions)
  actions.reject { |action| action[:played] }.each do |action|
    play_action(action)
  end
end

#process_any_content(**opts) ⇒ Object

Process content will take any one of the following

- Raw content
- File based content
- Raw template (translated via handlebars)
- File base template (translated via handlebars)

Process any of the above inputs to create final content output

Parameters:

  • opts (Hash)

    a customizable set of options

Options Hash (**opts):

  • :content (String)

    Supply the content that you want to write to the file

  • :template (String)

    Supply the template that you want to write to the file, template will be transformed using handlebars

  • :content_file (String)

    File with content, file location is based on where the program is running

  • :template_file (String)

    File with handlebars templated content that will be transformed, file location is based on the configured template_path



513
514
515
516
517
518
519
520
521
522
# File 'lib/k_builder/base_builder.rb', line 513

def process_any_content(**opts)
  raw_content = use_content(**opts)

  return raw_content if raw_content

  template_content = use_template(**opts)

  Handlebarsjs.render(template_content, opts) unless template_content.nil?
  # Handlebars::Helpers::Template.render(template_content, opts) unless template_content.nil?
end

#run_action(action) ⇒ Object

certain actions (e.g. set_current_folder) will run independently to play rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/k_builder/base_builder.rb', line 175

def run_action(action)
  case action[:action]
  when :add_file
    add_file(action[:file], **action[:opts])
  when :delete_file
    delete_file(action[:file], action[:opts])
  when :add_clipboard
    add_clipboard(action[:opts])
  when :vscode
    vscode(action[:file_parts], action[:opts])
  when :browse
    browse(action[:file_parts], action[:opts])
  when :set_current_folder
    set_current_folder(action[:folder_key])
  when :run_command
    run_command(action[:command])
  when :run_script
    run_script(action[:script])
  else
    log.error "Unknown action: #{action[:action]}"
  end
end

#run_command(command) ⇒ Object Also known as: rc



547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/k_builder/base_builder.rb', line 547

def run_command(command)
  # Deep path create if needed
  tf = target_folder

  mkdir_p(tf)

  build_command = "cd #{tf} && #{command}"

  puts build_command

  # need to support the fork process options as I was not able to run
  # k_builder_watch -n because it hid all the following output
  system(build_command)

  # FROM k_dsl
  # system "/usr/local/bin/zsh #{output_file}" if execution_context == :system
  # fork { exec("/usr/local/bin/zsh #{output_file}") } if execution_context == :fork
end

#run_command_action(command) ⇒ Object



567
568
569
570
571
572
573
# File 'lib/k_builder/base_builder.rb', line 567

def run_command_action(command)
  {
    action: :run_command,
    played: false,
    command: command
  }
end

#run_cop(file, **opts) ⇒ Object

Usage

Dir.chdir(k_builder.target_folders.get(:app)) do

k_builder.run_cop('**/*.rb', fix_unsafe: true)

end



531
532
533
534
535
536
# File 'lib/k_builder/base_builder.rb', line 531

def run_cop(file, **opts)
  command = Commands::RuboCopCommand.new(file, builder: self, **opts)
  command.execute

  self
end

#run_prettier(file, log_level: :log) ⇒ Object

Need to handle absolute files, see /Users/davidcruwys/dev/printspeak/reference_application/printspeak-domain/.builders/presentation/presentation_builder/commands/copy_ruby_resource_command.rb



540
541
542
543
544
545
# File 'lib/k_builder/base_builder.rb', line 540

def run_prettier(file, log_level: :log)
  # command = "prettier --check #{file} --write #{file}"
  command = "npx prettier --loglevel #{log_level} --write #{file}"

  run_command command
end

#run_script(script) ⇒ Object

NOT TESTED, and not working with opts, this code needs rewrite



576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
# File 'lib/k_builder/base_builder.rb', line 576

def run_script(script)
  # Deep path create if needed
  tf = target_folder

  mkdir_p(tf)

  Dir.chdir(tf) do
    output, status = Open3.capture2(script) # , **opts)

    unless status.success?
      log.error('Script failed')
      puts script
      return nil
    end

    return output
  end
end

#run_script_action(script) ⇒ Object



595
596
597
598
599
600
601
# File 'lib/k_builder/base_builder.rb', line 595

def run_script_action(script)
  {
    action: :run_script,
    played: false,
    script: script
  }
end

#set_current_folder(folder_key) ⇒ Object Also known as: cd



379
380
381
382
383
# File 'lib/k_builder/base_builder.rb', line 379

def set_current_folder(folder_key)
  target_folders.current = folder_key

  self
end

#set_current_folder_action(folder_key) ⇒ Object

Target folders and files




371
372
373
374
375
376
377
# File 'lib/k_builder/base_builder.rb', line 371

def set_current_folder_action(folder_key)
  {
    action: :set_current_folder,
    played: false,
    folder_key: folder_key
  }
end

#target_file(*file_parts, folder_key: current_folder_key, folder: nil) ⇒ Object

Get target file

If you provide a relative folder, then it will be relative to the :folder parameter

If the :folder is not set, then it will be relative to the current folder

If you provide an absolute folder, then it will ignore the :folder parameter



421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'lib/k_builder/base_builder.rb', line 421

def target_file(*file_parts, folder_key: current_folder_key, folder: nil, **)
  # TODO: Mismatch (sometimes called folder, sometimes called folder_key:)
  if folder
    log.error("Change folder: to folder_key: for #{folder} - #{file_parts}")
    return
  end

  # Absolute path
  return File.join(*file_parts) if Pathname.new(file_parts.first).absolute?

  # Relative to :folder_key
  File.join(target_folder(folder_key), *file_parts)
end

#target_folder(folder_key = current_folder_key) ⇒ Object

Get target folder by folder_key

If folder_key not supplied then get the current target folder



400
401
402
# File 'lib/k_builder/base_builder.rb', line 400

def target_folder(folder_key = current_folder_key)
  target_folders.get(folder_key)
end

#to_hObject



72
73
74
75
76
77
# File 'lib/k_builder/base_builder.rb', line 72

def to_h
  {
    target_folders: target_folders.to_h,
    template_folders: template_folders.to_h
  }
end

#use_content(**opts) ⇒ Object

Use content from a a selection of content sources

Future options

Parameters:

  • opts (Hash)

    a customizable set of options

Options Hash (**opts):

  • :content (String)

    Just pass through the :content as is.

  • :content_file (String)

    Read content from the :content_file

  • :content_loren (String)

    [TODO]Create Loren Ipsum text as a :content_loren count of words

  • :content_url (String)

    Read content from the :content_url

Returns:

  • Returns some content



470
471
472
473
474
475
476
477
478
479
480
481
# File 'lib/k_builder/base_builder.rb', line 470

def use_content(**opts)
  return opts[:content] unless opts[:content].nil?

  return unless opts[:content_file]

  # NOTE: when using content file, you still want to search for it in the template folders, I THINK?
  cf = find_template_file(opts[:content_file])

  return "content not found: #{opts[:content_file]}" if cf.nil?

  File.read(cf)
end

#use_template(**opts) ⇒ Object

Use template from a a selection of template sources

Parameters:

  • opts (Hash)

    a customizable set of options

Options Hash (**opts):

  • :template (String)

    Just pass through the :template as is.

  • :template_file (String)

    Read template from the :template_file

Returns:

  • Returns some template



489
490
491
492
493
494
495
496
497
498
499
# File 'lib/k_builder/base_builder.rb', line 489

def use_template(**opts)
  return opts[:template] unless opts[:template].nil?

  return unless opts[:template_file]

  tf = find_template_file(opts[:template_file])

  return "template not found: #{opts[:template_file]}" if tf.nil?

  File.read(tf)
end

#vscode(*file_parts, folder_key: current_folder_key, file: nil) ⇒ Object



289
290
291
292
293
294
295
296
# File 'lib/k_builder/base_builder.rb', line 289

def vscode(*file_parts, folder_key: current_folder_key, file: nil)
  # move to command
  file = target_file(*file_parts, folder_key: folder_key) if file.nil?

  rc "code #{file}"

  self
end

#vscode_action(*file_parts, folder_key: current_folder_key, file: nil) ⇒ Object



280
281
282
283
284
285
286
287
# File 'lib/k_builder/base_builder.rb', line 280

def vscode_action(*file_parts, folder_key: current_folder_key, file: nil)
  {
    action: :vscode,
    played: false,
    file_parts: file_parts,
    opts: { folder_key: folder_key, file: file }
  }
end

#vscompare(file, content) ⇒ Object



625
626
627
628
629
630
631
632
633
634
635
636
637
638
# File 'lib/k_builder/base_builder.rb', line 625

def vscompare(file, content)
  # need to use some sort of caching folder for this
  ext = File.extname(file)
  fn  = File.basename(file, ext)
  temp_file = Tempfile.new([fn, ext])

  temp_file.write(content)
  temp_file.close

  return if File.read(file) == content

  system("code -d #{file} #{temp_file.path}")
  sleep 2
end