k_builder 0.0.1 → 0.0.14

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: d63754fbda587b7ea17d7ae17d4fb33029fac853280ce5125bfb1d7924c4ddfc
4
- data.tar.gz: 62d174cd9cf2b5ad60a43319875efffc6845a409ea1067b4cb01d916f69456cf
3
+ metadata.gz: ff2053d7113bdfdf11d6289f81220840a742362b20a5ee4283a995eff8010101
4
+ data.tar.gz: f3a70c18493de81b6b5eebaf90555ce222cb2144825aeb154265f4704a9cd43e
5
5
  SHA512:
6
- metadata.gz: 53b98c935cb446629725ccb9a4bd4fa6babe87e985e7886ab2308592cb5413604063cb54eee5f439dfe79263b3d73d03c32c94cbe9ccb89eaf0599b1c655e9ea
7
- data.tar.gz: 985ad06c8e9a92f5e79eab2167b35cebee0940ae87bd9044e3de466c09786364444cbffafe7441bef59f8d031186106ffc317d9ddc91dc6c9288066db670f548
6
+ metadata.gz: 20f67a1a1409f111b4d76c6bd45858342d6d04c82e60f6b5d646e07eea64ff2a0630a290ef94832e09181528d1d86143b0635717a33f06bcc84d12c55d93d8fb
7
+ data.tar.gz: 6527ac296eb3f43f89bfad8028084adbe89412ebb3547143a8c0a6771e1af95ae06805d79ce696f428ac5e955b444e96dbb0dec399b12d2e0c525c11956a23b5
data/.rubocop.yml CHANGED
@@ -60,6 +60,9 @@ Naming/MemoizedInstanceVariableName:
60
60
  Naming/VariableNumber:
61
61
  Exclude:
62
62
  - "**/spec/**/*"
63
+ Naming/AccessorMethodName:
64
+ Exclude:
65
+ - "**/*builder*.rb"
63
66
  Style/EmptyMethod:
64
67
  Exclude:
65
68
  - "**/spec/**/*"
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_builder.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_builder/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
23
+ watch(%r{^lib/k_builder/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
@@ -2,6 +2,29 @@
2
2
 
3
3
  > K Builder provides various fluent builders for initializing applications with different language requirements
4
4
 
5
+ ## ToDo
6
+
7
+ - BuildWatcher (as a builder)
8
+ - AppBuilder
9
+ - BaseBuilder
10
+ - WebBuilder
11
+ - PackageBuilder
12
+ - Webpack5Builder
13
+ - ReactBuilder
14
+ - SlideDeckBuilder
15
+ - JavscriptBuilder
16
+ - SolutionBuilder
17
+ - DotnetBuilder
18
+ - C#Console
19
+ - C#Mvc
20
+ - RubyBuilder
21
+ - RubyGem
22
+ - RailsApp
23
+ - PythonBuilder
24
+ - DddBuilder
25
+ - DddGenerator
26
+
27
+
5
28
  ## Installation
6
29
 
7
30
  Add this line to your application's Gemfile:
@@ -26,16 +49,23 @@ gem install k_builder
26
49
 
27
50
  ### Main Story
28
51
 
29
-
52
+ As a Polyglot Developer, I want to be up and running in any development language with consistency, so I am productive and using best practices
30
53
 
31
54
  See all [stories](./STORIES.md)
32
55
 
33
-
34
56
  ## Usage
35
57
 
36
58
  See all [usage examples](./USAGE.md)
37
59
 
60
+ ### Basic Example
38
61
 
62
+ #### Basic example
63
+
64
+ Description for a basic example to be featured in the main README.MD file
65
+
66
+ ```ruby
67
+ class SomeRuby; end
68
+ ```
39
69
 
40
70
  ## Development
41
71
 
@@ -45,7 +75,7 @@ Checkout the repo
45
75
  git clone klueless-io/k_builder
46
76
  ```
47
77
 
48
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
78
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
49
79
 
50
80
  You can also run `bin/console` for an interactive prompt that will allow you to experiment.
51
81
 
data/STORIES.md CHANGED
@@ -8,26 +8,21 @@ As a Polyglot Developer, I want to be up and running in any development language
8
8
 
9
9
  ### Stories next on list
10
10
 
11
- As a Developer, I can DO_SOMETHING, so that I QUALITY_OF_LIFE
12
-
13
- - Subtask
11
+ As a Polyglot Developer, I want to be up and running in any development language with consistency, so I am productive and using best practices [EPIC]
14
12
 
15
13
  ### Tasks next on list
16
14
 
17
- Setup RubyGems and RubyDoc
18
-
19
- - Build and deploy gem to [rubygems.org](https://rubygems.org/gems/k_builder)
20
- - Attach documentation to [rubydoc.info](https://rubydoc.info/github/to-do-/k_builder/master)
21
-
22
- Setup GitHub Action (test and lint)
23
-
24
- - Setup Rspec action
25
- - Setup RuboCop action
15
+ BaseBuilder
26
16
 
27
17
  ## Stories and tasks
28
18
 
29
19
  ### Tasks - completed
30
20
 
21
+ Setup RubyGems and RubyDoc
22
+
23
+ - Build and deploy gem to [rubygems.org](https://rubygems.org/gems/k_builder)
24
+ - Attach documentation to [rubydoc.info](https://rubydoc.info/github/to-do-/k_builder/master)
25
+
31
26
  Setup project management, requirement and SCRUM documents
32
27
 
33
28
  - Setup readme file
@@ -35,6 +30,11 @@ Setup project management, requirement and SCRUM documents
35
30
  - Setup a project backlog
36
31
  - Setup an examples/usage document
37
32
 
33
+ Setup GitHub Action (test and lint)
34
+
35
+ - Setup Rspec action
36
+ - Setup RuboCop action
37
+
38
38
  Setup new Ruby GEM
39
39
 
40
40
  - Build out a standard GEM structure
data/k_builder.gemspec CHANGED
@@ -38,5 +38,6 @@ Gem::Specification.new do |spec|
38
38
  spec.require_paths = ['lib']
39
39
  # spec.extensions = ['ext/k_builder/extconf.rb']
40
40
 
41
+ spec.add_dependency 'handlebars-helpers', '~> 0'
41
42
  # spec.add_dependency 'tty-box', '~> 0.5.0'
42
43
  end
data/lib/k_builder.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'k_builder/version'
4
+ require 'k_builder/configuration'
5
+ require 'k_builder/base_builder'
6
+ require 'k_builder/builder'
7
+
8
+ require 'handlebars/helpers/template'
4
9
 
5
10
  module KBuilder
6
11
  # raise KBuilder::Error, 'Sample message'
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBuilder
4
+ # Base builder defines builder methods, build method and configuration
5
+ #
6
+ # Convention: Setter methods (are Fluent) and use the prefix set_
7
+ # Getter methods (are NOT fluent) and return the stored value
8
+ # Setter methods (are NOT fluent) can be created as needed
9
+ # these methods would not be prefixed with the set_
10
+ class BaseBuilder
11
+ attr_reader :hash
12
+
13
+ # Factory method that provides a builder for a specified structure
14
+ # runs through a configuration block and then builds the final structure
15
+ #
16
+ # @return [type=Object] data structure
17
+ def self.build
18
+ init.build
19
+ end
20
+
21
+ # Create and initialize the builder.
22
+ #
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
+ # @return [Builder] Returns the builder via fluent interface
29
+ def self.init(configuration = nil)
30
+ builder = new(configuration)
31
+
32
+ builder.after_new
33
+
34
+ yield(builder) if block_given?
35
+
36
+ builder
37
+ end
38
+
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
+ # assigns a builder hash and defines builder methods
46
+ def initialize(configuration = nil)
47
+ @hash = {}
48
+
49
+ unless configuration.nil?
50
+ raise KBuilder::StandardError, 'Unknown configuration object' unless configuration.is_a?(Hash)
51
+
52
+ hash.merge!(configuration)
53
+ end
54
+
55
+ define_builder_setter_methods
56
+ end
57
+
58
+ # Return an array of symbols to represent the fluent
59
+ # setter methods that you want on your builder.
60
+ #
61
+ # Abstract method
62
+ def builder_setter_methods
63
+ raise NotImplementedError
64
+ end
65
+
66
+ # @return [Hash/StrongType] Returns data object, can be a hash
67
+ # or strong typed object that you
68
+ # have wrapped around the hash
69
+ def build
70
+ hash
71
+ end
72
+
73
+ # builds a nested structure by either builder block or hash
74
+ # @param data_structure [type=DataStructure]
75
+ # @param builder [type=Builder]
76
+ # @param attributes [type=Hash|DataStructure instance]
77
+ # @param &block
78
+ #
79
+ # @return [type=Hash]
80
+ def build_nested(data_structure, builder, attributes = {}, &block)
81
+ if block_given?
82
+ builder.build(&block).to_h
83
+ else
84
+ build_hash(data_structure, attributes)
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ #
91
+ # @param data_structure [type=DataStructure]
92
+ # @param attributes [type=Hash, DataStructure]
93
+ #
94
+ # @return [type=Hash]
95
+ def build_hash(data_structure, attributes)
96
+ if attributes.is_a?(data_structure)
97
+ attributes.to_h
98
+ else
99
+ data_structure.new(attributes).to_h
100
+ end
101
+ end
102
+
103
+ # Defines all of the necessary builder setter methods
104
+ #
105
+ # @return [Builder] Returns the builder via fluent interface
106
+ def define_builder_setter_methods
107
+ builder_setter_methods.each { |method| define_builder_method(method) }
108
+ self
109
+ end
110
+
111
+ # Defines a method using the convention set_[method_name]
112
+ #
113
+ # Convention: Setter methods (are Fluent) and use the prefix set_
114
+ # Getter methods (are NOT fluent) and return the stored value
115
+ #
116
+ # @return [Builder] Returns the builder via fluent interface
117
+ def define_builder_method(method_name)
118
+ self.class.send(:define_method, "set_#{method_name}") do |value|
119
+ @hash[method_name.to_s] = value
120
+ self
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,252 @@
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
+ def template_folder=(value)
109
+ hash['template_folder'] = File.expand_path(value)
110
+ end
111
+
112
+ # Getter for template folder
113
+ def template_folder
114
+ hash['template_folder']
115
+ end
116
+
117
+ # Global Target folder
118
+ # ----------------------------------------------------------------------
119
+
120
+ # Fluent setter for global template folder
121
+ def set_global_template_folder(value)
122
+ self.global_template_folder = value
123
+
124
+ self
125
+ end
126
+
127
+ # Setter for global template folder
128
+ def global_template_folder=(value)
129
+ hash['global_template_folder'] = File.expand_path(value)
130
+ end
131
+
132
+ # Setter for global template folder
133
+ def global_template_folder
134
+ hash['global_template_folder']
135
+ end
136
+
137
+ # Internal Actions are considered helpers for the builder, they do
138
+ # something useful, but they do not tend to implement fluent interfaces.
139
+ #
140
+ # They some times do actions, they sometimes return information.
141
+ #
142
+ # NOTE: [SRP] - These methods should probably be converted into objects
143
+ # ----------------------------------------------------------------------
144
+
145
+ # Gets a target_file relative to target folder
146
+ def target_file(file)
147
+ File.join(target_folder, file)
148
+ end
149
+
150
+ # Gets a template_file relative to the template folder
151
+ def template_file(file)
152
+ File.join(template_folder, file)
153
+ end
154
+
155
+ # Gets a global_template_file relative to the global template folder
156
+ def global_template_file(file)
157
+ File.join(global_template_folder, file)
158
+ end
159
+
160
+ # Gets a template_file relative to the template folder, looks first in
161
+ # local template folder and if not found, looks in global template folder
162
+ def find_template_file(file)
163
+ full_file = template_file(file)
164
+ return full_file if File.exist?(full_file)
165
+
166
+ full_file = global_template_file(file)
167
+ return full_file if File.exist?(full_file)
168
+
169
+ # File not found
170
+ nil
171
+ end
172
+
173
+ # Use content from a a selection of content sources
174
+ #
175
+ # @option opts [String] :content Just pass through the :content as is.
176
+ # @option opts [String] :content_file Read content from the :content_file
177
+ #
178
+ # Future options
179
+ # @option opts [String] :content_loren [TODO]Create Loren Ipsum text as a :content_loren count of words
180
+ # @option opts [String] :content_url Read content from the :content_url
181
+ #
182
+ # @return Returns some content
183
+ def use_content(**opts)
184
+ return opts[:content] unless opts[:content].nil?
185
+
186
+ return unless opts[:content_file]
187
+
188
+ cf = opts[:content_file]
189
+
190
+ return "Content not found: #{File.expand_path(cf)}" unless File.exist?(cf)
191
+
192
+ File.read(cf)
193
+ end
194
+
195
+ # Use template from a a selection of template sources
196
+ #
197
+ # @option opts [String] :template Just pass through the :template as is.
198
+ # @option opts [String] :template_file Read template from the :template_file
199
+ #
200
+ # @return Returns some template
201
+ def use_template(**opts)
202
+ return opts[:template] unless opts[:template].nil?
203
+
204
+ return unless opts[:template_file]
205
+
206
+ tf = find_template_file(opts[:template_file])
207
+
208
+ return "template not found: #{opts[:template_file]}" if tf.nil?
209
+
210
+ File.read(tf)
211
+ end
212
+
213
+ # Process content will take any one of the following
214
+ # - Raw content
215
+ # - File based content
216
+ # - Raw template (translated via handlebars)
217
+ # - File base template (translated via handlebars)
218
+ #
219
+ # Process any of the above inputs to create final content output
220
+ #
221
+ # @option opts [String] :content Supply the content that you want to write to the file
222
+ # @option opts [String] :template Supply the template that you want to write to the file, template will be transformed using handlebars
223
+ # @option opts [String] :content_file File with content, file location is based on where the program is running
224
+ # @option opts [String] :template_file File with handlebars templated content that will be transformed, file location is based on the configured template_path
225
+ def process_any_content(**opts)
226
+ raw_content = use_content(**opts)
227
+
228
+ return raw_content if raw_content
229
+
230
+ template_content = use_template(**opts)
231
+
232
+ Handlebars::Helpers::Template.render(template_content, opts) unless template_content.nil?
233
+ end
234
+
235
+ def run_prettier(file, log_level: :log)
236
+ # command = "prettier --check #{file} --write #{file}"
237
+ command = "prettier --loglevel #{log_level} --write #{file}"
238
+
239
+ run_command command
240
+ end
241
+
242
+ def run_command(command)
243
+ # Deep path create if needed
244
+ FileUtils.mkdir_p(target_folder)
245
+
246
+ build_command = "cd #{target_folder} && #{command}"
247
+
248
+ system(build_command)
249
+ end
250
+ alias rc run_command
251
+ end
252
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Attach configuration to the KBuilder module
4
+ module KBuilder
5
+ # Configuration for webpack5/builder
6
+ class << self
7
+ attr_writer :configuration
8
+ end
9
+
10
+ def self.configuration
11
+ @configuration ||= Configuration.new
12
+ end
13
+
14
+ def self.reset
15
+ @configuration = Configuration.new
16
+ end
17
+
18
+ def self.configure
19
+ yield(configuration)
20
+ end
21
+
22
+ # Configuration class
23
+ class Configuration
24
+ attr_accessor :target_folder
25
+ attr_accessor :template_folder
26
+ attr_accessor :global_template_folder
27
+
28
+ def initialize
29
+ @target_folder = Dir.getwd
30
+ @template_folder = File.join(Dir.getwd, '.templates')
31
+ @global_template_folder = nil
32
+ end
33
+
34
+ def debug
35
+ puts '-' * 120
36
+ puts 'kbuilder base configuration'
37
+ kv 'target_folder' , target_folder
38
+ kv 'template_folder' , template_folder
39
+ kv 'global_template_folder', global_template_folder
40
+ end
41
+
42
+ def to_hash
43
+ hash = {}
44
+ instance_variables.each { |var| hash[var.to_s.delete('@')] = instance_variable_get(var) }
45
+ hash
46
+ end
47
+
48
+ private
49
+
50
+ def kv(name, value)
51
+ puts "#{name.rjust(30)} : #{value}"
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KBuilder
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.14'
5
5
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: k_builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.14
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-10 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: handlebars-helpers
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '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'
13
27
  description: " K Builder provides various fluent builders for initializing applications
14
28
  with different language requirements\n"
15
29
  email:
@@ -24,6 +38,7 @@ files:
24
38
  - ".rubocop.yml"
25
39
  - CODE_OF_CONDUCT.md
26
40
  - Gemfile
41
+ - Guardfile
27
42
  - LICENSE.txt
28
43
  - README.md
29
44
  - Rakefile
@@ -38,6 +53,9 @@ files:
38
53
  - hooks/update-version
39
54
  - k_builder.gemspec
40
55
  - lib/k_builder.rb
56
+ - lib/k_builder/base_builder.rb
57
+ - lib/k_builder/builder.rb
58
+ - lib/k_builder/configuration.rb
41
59
  - lib/k_builder/version.rb
42
60
  homepage: http://appydave.com/gems/k-builder
43
61
  licenses: