planter-cli 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'fileutils'
5
+
6
+ describe Planter::Script do
7
+ let(:template_dir) { File.expand_path('spec/templates/test') }
8
+ let(:output_dir) { File.expand_path('spec/test_out') }
9
+ let(:script_name) { 'test.sh' }
10
+ let(:script_name_fail) { 'test_fail.sh' }
11
+ let(:script_path) { File.join(template_dir, '_scripts', script_name) }
12
+ let(:base_script_path) { File.join(Planter.base_dir, 'scripts', script_name) }
13
+
14
+ before do
15
+ Planter.base_dir = File.expand_path('spec')
16
+ allow(File).to receive(:exist?).and_call_original
17
+ allow(File).to receive(:directory?).and_call_original
18
+ allow(File).to receive(:exist?).with(script_path).and_return(true)
19
+ allow(File).to receive(:exist?).with(base_script_path).and_return(false)
20
+ allow(File).to receive(:directory?).with(output_dir).and_return(true)
21
+ end
22
+
23
+ describe '#initialize' do
24
+ it 'initializes with valid script and directories' do
25
+ script = Planter::Script.new(template_dir, output_dir, script_name)
26
+ expect(script.script).to eq(script_path)
27
+ end
28
+
29
+ it 'raises an error if script is not found' do
30
+ allow(File).to receive(:exist?).with(script_path).and_return(false)
31
+ expect do
32
+ Planter::Script.new(template_dir, output_dir, script_name)
33
+ end.to raise_error(ScriptError)
34
+ end
35
+
36
+ it 'raises an error if output directory is not found' do
37
+ allow(File).to receive(:directory?).with(output_dir).and_return(false)
38
+ expect do
39
+ Planter::Script.new(template_dir, output_dir, script_name)
40
+ end.to raise_error(ScriptError)
41
+ end
42
+ end
43
+
44
+ describe '#find_script' do
45
+ it 'finds the script in the template directory' do
46
+ script = Planter::Script.new(template_dir, output_dir, script_name)
47
+ expect(script.find_script(template_dir, script_name)).to eq(script_path)
48
+ end
49
+
50
+ it 'finds the script in the base directory' do
51
+ allow(File).to receive(:exist?).with(script_path).and_return(false)
52
+ allow(File).to receive(:exist?).with(base_script_path).and_return(true)
53
+ script = Planter::Script.new(template_dir, output_dir, script_name)
54
+ expect(script.find_script(template_dir, script_name)).to eq(base_script_path)
55
+ end
56
+
57
+ it 'returns nil if script is not found' do
58
+ allow(File).to receive(:exist?).with(script_path).and_return(false)
59
+ allow(File).to receive(:exist?).with(base_script_path).and_return(false)
60
+ expect do
61
+ script = Planter::Script.new(template_dir, output_dir, script_name)
62
+ script.find_script(template_dir, script_name)
63
+ end.to raise_error(ScriptError)
64
+ end
65
+ end
66
+
67
+ describe '#run' do
68
+ it 'executes the script successfully' do
69
+ script = Planter::Script.new(template_dir, output_dir, script_name)
70
+ expect(script.run).to be true
71
+ end
72
+
73
+ it 'raises an error if script execution fails' do
74
+ script = Planter::Script.new(template_dir, output_dir, script_name_fail)
75
+ expect do
76
+ script.run
77
+ end.to raise_error(ScriptError)
78
+ end
79
+ end
80
+ end
@@ -9,12 +9,225 @@ describe ::String do
9
9
 
10
10
  describe '.to_slug' do
11
11
  it 'slugifies a string' do
12
- expect('This is a test string'.to_slug).to match /this-is-a-test-string/
12
+ expect('This is a test string'.to_slug).to match(/this-is-a-test-string/)
13
13
  end
14
14
 
15
15
  it 'slugifies bad characters' do
16
- expect('This: #is a test string!'.to_slug).to match /this-colon-hash-is-a-test-string-bang/
16
+ expect('This: #is a test string!'.to_slug).to match(/this-colon-hash-is-a-test-string-bang/)
17
17
  end
18
18
  end
19
19
 
20
+ describe '.to_class_name' do
21
+ it 'converts string to CamelCase' do
22
+ expect('this is a test string'.to_class_name).to eq 'ThisIsATestString'
23
+ end
24
+
25
+ it 'handles special characters' do
26
+ expect('this: #is a test string!'.to_class_name).to eq 'ThisIsATestString'
27
+ end
28
+ end
29
+
30
+ describe '.snake_case' do
31
+ it 'converts CamelCase to snake_case' do
32
+ expect('ThisIsATestString'.snake_case).to eq 'this_is_a_test_string'
33
+ end
34
+
35
+ it 'handles strings with spaces' do
36
+ expect('This is a test string'.snake_case).to eq 'this_is_a_test_string'
37
+ end
38
+
39
+ it 'handles strings with special characters' do
40
+ expect('This: #is a test string!'.snake_case).to eq 'this_is_a_test_string'
41
+ end
42
+ end
43
+
44
+ describe '.camel_case' do
45
+ it 'converts snake_case to CamelCase' do
46
+ expect('this_is_a_test_string'.camel_case).to eq 'thisIsATestString'
47
+ end
48
+
49
+ it 'handles strings with spaces' do
50
+ expect('this is a test string'.camel_case).to eq 'thisIsATestString'
51
+ end
52
+
53
+ it 'handles strings with special characters' do
54
+ expect('this: #is a test string!'.camel_case).to eq 'thisIsATestString'
55
+ end
56
+ end
57
+
58
+ describe '.title_case' do
59
+ it 'converts a string to Title Case' do
60
+ expect('this is a test string'.title_case).to eq 'This Is A Test String'
61
+ end
62
+
63
+ it 'handles strings with special characters' do
64
+ expect('this: #is a test string!'.title_case).to eq 'This: #Is A Test String!'
65
+ end
66
+
67
+ it 'handles mixed case strings' do
68
+ expect('ThIs Is A TeSt StRiNg'.title_case).to eq 'This Is A Test String'
69
+ end
70
+ end
71
+
72
+ describe '.apply_variables' do
73
+ it 'replaces placeholders with variable values' do
74
+ template = 'Hello, %%name%%!'
75
+ variables = { name: 'World' }
76
+ expect(template.apply_variables(variables: variables)).to eq 'Hello, World!'
77
+ end
78
+
79
+ it 'handles multiple variables' do
80
+ template = 'Hello, %%first_name%% %%last_name%%!'
81
+ variables = { first_name: 'John', last_name: 'Doe' }
82
+ expect(template.apply_variables(variables: variables)).to eq 'Hello, John Doe!'
83
+ end
84
+
85
+ it 'handles missing variables gracefully' do
86
+ template = 'Hello, %%name%%!'
87
+ variables = {}
88
+ expect(template.apply_variables(variables: variables)).to eq 'Hello, %%name%%!'
89
+ end
90
+
91
+ it 'handles variables with special characters' do
92
+ template = 'Hello, %%name%%!'
93
+ variables = { name: 'John #Doe' }
94
+ expect(template.apply_variables(variables: variables)).to eq 'Hello, John #Doe!'
95
+ end
96
+
97
+ it 'handles modifiers' do
98
+ template = 'Hello, %%title:upper%% %%name:title%%!'
99
+ variables = { title: 'Mr.', name: 'john do' }
100
+ expect(template.apply_variables(variables: variables)).to eq 'Hello, MR. John Do!'
101
+ end
102
+
103
+ it 'operates in place' do
104
+ template = 'Hello, %%title:upper%% %%name:title%%!'
105
+ variables = { title: 'Mr.', name: 'john do' }
106
+ template.apply_variables!(variables: variables)
107
+ expect(template).to eq 'Hello, MR. John Do!'
108
+ end
109
+
110
+ it 'handles last_only' do
111
+ template = 'Hello, %%title%% %%title:upper%%!'
112
+ variables = { title: 'project title' }
113
+ expect(template.apply_variables(variables: variables, last_only: true)).to eq 'Hello, %%title%% PROJECT TITLE!'
114
+ end
115
+ end
116
+
117
+ describe '.apply_regexes' do
118
+ it 'applies a single regex replacement' do
119
+ template = 'Hello, World!'
120
+ regexes = { /World/ => 'Universe' }
121
+ expect(template.apply_regexes(regexes)).to eq 'Hello, Universe!'
122
+ end
123
+
124
+ it 'applies multiple regex replacements' do
125
+ template = 'Hello, World! Welcome to the World!'
126
+ regexes = { /World/ => 'Universe', /Welcome/ => 'Greetings' }
127
+ expect(template.apply_regexes(regexes)).to eq 'Hello, Universe! Greetings to the Universe!'
128
+ end
129
+
130
+ it 'handles no regex replacements' do
131
+ template = 'Hello, World!'
132
+ regexes = {}
133
+ expect(template.apply_regexes(regexes)).to eq 'Hello, World!'
134
+ end
135
+
136
+ it 'handles special characters in regex' do
137
+ template = 'Hello, World! #Welcome to the World!'
138
+ regexes = { /#Welcome/ => 'Greetings' }
139
+ expect(template.apply_regexes(regexes)).to eq 'Hello, World! Greetings to the World!'
140
+ end
141
+
142
+ it 'Operates in place' do
143
+ template = 'Hello, World! #Welcome to the World!'
144
+ regexes = { /#Welcome/ => 'Greetings' }
145
+ template.apply_regexes!(regexes)
146
+ expect(template).to eq 'Hello, World! Greetings to the World!'
147
+ end
148
+ end
149
+
150
+ describe '.ext' do
151
+ it 'applies an extension' do
152
+ expect("filename.rb".ext('txt')).to eq 'filename.txt'
153
+ end
154
+
155
+ it 'ignores an existing extension' do
156
+ expect("filename.rb".ext('rb')).to eq 'filename.rb'
157
+ end
158
+ end
159
+
160
+ describe '.normalize_type' do
161
+ it 'normalizes a date type' do
162
+ expect("da".normalize_type.to_s).to eq "date"
163
+ end
164
+
165
+ it 'normalizes an integer type' do
166
+ expect("int".normalize_type.to_s).to eq "integer"
167
+ end
168
+
169
+ it 'normalizes a float type' do
170
+ expect("f".normalize_type.to_s).to eq "float"
171
+ end
172
+
173
+ it 'normalizes a multiline type' do
174
+ expect("multi".normalize_type.to_s).to eq "multiline"
175
+ end
176
+
177
+ it 'normalizes a class type' do
178
+ expect("c".normalize_type.to_s).to eq "class"
179
+ end
180
+
181
+ it 'normalizes a module type' do
182
+ expect("m".normalize_type.to_s).to eq "module"
183
+ end
184
+ end
185
+
186
+ describe '.normalize_operator' do
187
+ it 'normalizes a copy operator' do
188
+ expect("copy".normalize_operator.to_s).to eq "copy"
189
+ end
190
+ end
191
+
192
+ describe '.coerce' do
193
+ it 'coerces a date type' do
194
+ expect("now".coerce(:date)).to match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}/)
195
+ end
196
+
197
+ it 'coerces an integer type' do
198
+ expect("10".coerce(:integer)).to eq 10
199
+ end
200
+
201
+ it 'coerces a float type' do
202
+ expect("10.0".coerce(:float)).to eq 10.0
203
+ end
204
+
205
+ it 'coerces a multiline type' do
206
+ expect("multi\nline".coerce(:multiline)).to eq "multi\nline"
207
+ end
208
+
209
+ it 'coerces a class type' do
210
+ expect("Some class".coerce(:class)).to eq "SomeClass"
211
+ end
212
+ end
213
+
214
+ describe '.clean_encode!' do
215
+ it 'cleans an encoded string' do
216
+ s = "This is a test string"
217
+ s.clean_encode!
218
+ expect(s).to eq "This is a test string"
219
+ end
220
+ end
221
+
222
+ describe '.highlight_character' do
223
+ it 'highlights characters' do
224
+ s = "(o)ption 1 (s)econd option"
225
+ expect(s.highlight_character).to eq "{dw}({xbw}o{dw}){xw}ption 1 {dw}({xbw}s{dw}){xw}econd option"
226
+ end
227
+
228
+ it 'highlights characters with default option' do
229
+ s = "(o)ption 1 (s)econd option"
230
+ expect(s.highlight_character(default: 's')).to eq "{dw}({xbw}o{dw}){xw}ption 1 {dw}({xbc}s{dw}){xw}econd option"
231
+ end
232
+ end
20
233
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ::Symbol do
6
+ describe '.to_var' do
7
+ it 'turns a symbol into a string with _ instead of :' do
8
+ expect(:var_name.to_var).to eq :var_name
9
+ end
10
+ end
11
+
12
+ describe '.normalize_type' do
13
+ it 'normalizes a type symbol' do
14
+ expect(:string.normalize_type).to eq :string
15
+ end
16
+ end
17
+
18
+ describe '.normalize_operator' do
19
+ it 'normalizes an operator symbol' do
20
+ expect(:copy.normalize_operator).to eq :copy
21
+ end
22
+ end
23
+ end
data/spec/planter.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ defaults: false
3
+ git_init: false
4
+ files:
5
+ _planter.yml: ignore
6
+ color: true
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe "Planter" do
6
+ describe '.notify' do
7
+ it 'prints a warning message stderr' do
8
+ expect(Planter.notify('hello world', :warn)).to be true
9
+ end
10
+
11
+ it 'prints an info message stderr' do
12
+ expect(Planter.notify('hello world', :info)).to be true
13
+ end
14
+
15
+ it 'prints a debug message to stderr' do
16
+ Planter.debug = true
17
+ expect(Planter.notify('hello world', :debug)).to be true
18
+ end
19
+
20
+ it 'does not print a debug message to stderr' do
21
+ Planter.debug = false
22
+ expect(Planter.notify('hello world', :debug)).to be false
23
+ end
24
+
25
+ it 'prints an error message and exits' do
26
+ expect do
27
+ Planter.notify('Error', :error, exit_code: 10)
28
+ end.to raise_error(SystemExit)
29
+ end
30
+ end
31
+
32
+ describe '.config=' do
33
+ # it 'sets the config' do
34
+ # path = File.expand_path('spec/noop')
35
+ # FileUtils.mkdir_p(path)
36
+ # Planter.base_dir = File.expand_path('spec/noop')
37
+ # allow(File).to receive(:open).with(File.join(Planter.base_dir, "config.yml"), 'w')
38
+ # allow(File).to receive(:open).with(File.join(Planter.base_dir, 'templates', 'test', '_planter.yml'),
39
+ # 'w')
40
+ # Planter.config = 'test'
41
+ # expect(File.exist?('spec/noop/config.yml')).to be true
42
+ # FileUtils.remove_entry_secure(path)
43
+ # end
44
+ #
45
+ # it 'creates a new configuration file if it does not exist' do
46
+ # path = File.expand_path('spec/noop')
47
+ # FileUtils.mkdir_p(path)
48
+ # Planter.base_dir = File.expand_path('spec/noop')
49
+ # allow(File).to receive(:exist?).with(File.join(Planter.base_dir, 'config.yml')).and_return(false)
50
+ # expect(File).to receive(:open).with(File.join(Planter.base_dir, 'config.yml'), 'w')
51
+ # Planter.config = 'test'
52
+ # FileUtils.remove_entry_secure(path)
53
+ # end
54
+
55
+ # it 'creates a new template directory if it does not exist' do
56
+ # path = File.expand_path('spec/noop')
57
+ # FileUtils.mkdir_p(path)
58
+ # Planter.base_dir = File.expand_path('spec/noop')
59
+ # allow(File).to receive(:exist?).with(File.join(Planter.base_dir, 'templates', 'test',
60
+ # '_planter.yml')).and_return(false)
61
+ # allow(File).to receive(:directory?).with(File.join(Planter.base_dir, 'templates', 'test')).and_return(false)
62
+ # expect(FileUtils).to receive(:mkdir_p).with(File.join(Planter.base_dir, 'templates', 'test'))
63
+ # Planter.config = 'test'
64
+ # FileUtils.remove_entry_secure(path)
65
+ # end
66
+ end
67
+ end
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ echo "Oops"
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ exit 128
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'simplecov'
2
+ require 'cli-test'
3
+ require 'fileutils'
2
4
 
3
5
  SimpleCov.start
4
6
 
@@ -13,8 +15,12 @@ require 'planter'
13
15
 
14
16
  RSpec.configure do |c|
15
17
  c.expect_with(:rspec) { |e| e.syntax = :expect }
16
- c.before(:each) do
18
+ c.before do
19
+ ENV["RUBYOPT"] = '-W1'
20
+ ENV['PLANTER_DEBUG'] = 'true'
21
+ Planter.base_dir = File.expand_path('spec')
17
22
  allow(FileUtils).to receive(:remove_entry_secure).with(anything)
23
+ allow(FileUtils).to receive(:mkdir_p).with(anything)
18
24
  end
19
- c.add_formatter 'Fuubar'
25
+ c.add_formatter 'd'
20
26
  end
@@ -0,0 +1,12 @@
1
+ ---
2
+ variables:
3
+ - key: var_key
4
+ prompt: CLI Prompt
5
+ type: "[string, float, integer, number, date]"
6
+ value: "(optional, for date type can be today, time, now, etc., empty to prompt)"
7
+ default: "(optional default value, leave empty or remove key for no default)"
8
+ min: "(optional, for number type set a minimum value)"
9
+ max: "(optional, for number type set a maximum value)"
10
+ git_init: false
11
+ files:
12
+ "*.tmp": ignore
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ echo "Oops"
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ exit 128
Binary file
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ def test
4
+ puts "test"
5
+ end
data/src/_README.md CHANGED
@@ -19,7 +19,7 @@ If [Gum](https://github.com/charmbracelet/gum) is available it will be used for
19
19
 
20
20
  ## Configuration
21
21
 
22
- Planter's base configuration is in `~/.config/planter/config.yml`. This file can contain any of the keys used in templates (see below) and will serve as a base configuration for all templates. Any key defined in this file will be overridden if it exists in a template.
22
+ Planter's base configuration is in `~/.config/planter/planter.yml`. This file can contain any of the keys used in templates (see below) and will serve as a base configuration for all templates. Any key defined in this file will be overridden if it exists in a template.
23
23
 
24
24
  ### Scripts.
25
25
 
@@ -54,6 +54,10 @@ replacements: # Dictionary of pattern/replacments for regex substitution, see [R
54
54
  repo: # If a repository URL is provided, it will be pulled and duplicated instead of copying a file structure
55
55
  ```
56
56
 
57
+ #### Default values in template strings
58
+
59
+ In a template you can add a default value for a placholder by adding `%default value` to it. For example, `%%project%Default Project%%` will set the placeholder to `Default Project` if the variable value matches the default value in the configuration. This allows you to accept the default on the command line but have a different value inserted in the template. To use another variable in its place, use `$KEY` in the placeholder, e.g. `%%project%$title%%` will replace the `project` key with the value of `title` if the default is selected. Modifiers can be used on either side of the `%`, e.g. `%%project%$title:snake%%`.
60
+
57
61
  ### File-specific handling
58
62
 
59
63
  A `files` dictionary can specify how to handle specific files. Options are `copy`, `overwrite`, `merge`, or `ask`. The key for each entry is a filename or glob that matches the source filename (accounting for template variables if applicable):
@@ -72,6 +76,14 @@ Merged content
72
76
  // /merge
73
77
  ```
74
78
 
79
+ Or
80
+
81
+ ```
82
+ # merge
83
+ Merged content
84
+ # /merge
85
+ ```
86
+
75
87
  By default files that already exist in the destination directory are not overwritten, and merging allows you to add missing parts to a Rakefile or Makefile, for example.
76
88
 
77
89
  If `ask` is specified, a memu will be provided on the command line asking how to handle a file. If the file doesn't already exist, you will be asked only whether to copy the file or not. If it does exist, `overwrite` and `merge` options will be added.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: planter-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-28 00:00:00.000000000 Z
11
+ date: 2024-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bump
@@ -366,9 +366,26 @@ files:
366
366
  - scripts/deploy.rb
367
367
  - scripts/runtests.sh
368
368
  - spec/.rubocop.yml
369
+ - spec/config.yml
370
+ - spec/planter.yml
371
+ - spec/planter/array_spec.rb
372
+ - spec/planter/file_entry_spec.rb
373
+ - spec/planter/file_spec.rb
374
+ - spec/planter/filelist_spec.rb
375
+ - spec/planter/hash_spec.rb
369
376
  - spec/planter/plant_spec.rb
377
+ - spec/planter/script_spec.rb
370
378
  - spec/planter/string_spec.rb
379
+ - spec/planter/symbol_spec.rb
380
+ - spec/planter_spec.rb
381
+ - spec/scripts/test.sh
382
+ - spec/scripts/test_fail.sh
371
383
  - spec/spec_helper.rb
384
+ - spec/templates/test/_planter.yml
385
+ - spec/templates/test/_scripts/test.sh
386
+ - spec/templates/test/_scripts/test_fail.sh
387
+ - spec/test_out/image.png
388
+ - spec/test_out/test2.rb
372
389
  - src/_README.md
373
390
  homepage: https://github.com/ttscoff/planter-cli
374
391
  licenses:
@@ -389,12 +406,29 @@ required_rubygems_version: !ruby/object:Gem::Requirement
389
406
  - !ruby/object:Gem::Version
390
407
  version: '0'
391
408
  requirements: []
392
- rubygems_version: 3.2.16
409
+ rubygems_version: 3.2.15
393
410
  signing_key:
394
411
  specification_version: 4
395
412
  summary: Plant files and directories using templates
396
413
  test_files:
397
414
  - spec/.rubocop.yml
415
+ - spec/config.yml
416
+ - spec/planter.yml
417
+ - spec/planter/array_spec.rb
418
+ - spec/planter/file_entry_spec.rb
419
+ - spec/planter/file_spec.rb
420
+ - spec/planter/filelist_spec.rb
421
+ - spec/planter/hash_spec.rb
398
422
  - spec/planter/plant_spec.rb
423
+ - spec/planter/script_spec.rb
399
424
  - spec/planter/string_spec.rb
425
+ - spec/planter/symbol_spec.rb
426
+ - spec/planter_spec.rb
427
+ - spec/scripts/test.sh
428
+ - spec/scripts/test_fail.sh
400
429
  - spec/spec_helper.rb
430
+ - spec/templates/test/_planter.yml
431
+ - spec/templates/test/_scripts/test.sh
432
+ - spec/templates/test/_scripts/test_fail.sh
433
+ - spec/test_out/image.png
434
+ - spec/test_out/test2.rb