planter-cli 3.0.3 → 3.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.irbrc +2 -1
- data/.yardopts +1 -0
- data/CHANGELOG.md +28 -0
- data/README.md +142 -53
- data/bin/plant +6 -5
- data/lib/planter/array.rb +15 -1
- data/lib/planter/color.rb +7 -1
- data/lib/planter/config.rb +172 -0
- data/lib/planter/filelist.rb +12 -2
- data/lib/planter/numeric.rb +31 -0
- data/lib/planter/plant.rb +24 -17
- data/lib/planter/prompt.rb +23 -11
- data/lib/planter/script.rb +3 -3
- data/lib/planter/string.rb +150 -74
- data/lib/planter/tag.rb +38 -0
- data/lib/planter/version.rb +1 -1
- data/lib/planter.rb +39 -108
- data/lib/tty-spinner/lib/tty/spinner/multi.rb +3 -3
- data/planter-cli.gemspec +2 -0
- data/spec/cli_spec.rb +12 -2
- data/spec/planter/filelist_spec.rb +2 -2
- data/spec/planter/prompt_spec.rb +71 -0
- data/spec/planter/script_spec.rb +5 -4
- data/spec/planter/string_spec.rb +26 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/templates/test/_planter.yml +2 -0
- data/spec/templates/test/_scripts/plant.sh +3 -0
- data/src/_README.md +142 -53
- metadata +8 -2
data/lib/planter/plant.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
module Planter
|
4
4
|
# Primary class
|
5
5
|
class Plant
|
6
|
+
attr_reader :config
|
7
|
+
|
6
8
|
##
|
7
9
|
## Initialize a new Plant object
|
8
10
|
##
|
@@ -11,20 +13,24 @@ module Planter
|
|
11
13
|
##
|
12
14
|
def initialize(template = nil, variables = nil)
|
13
15
|
Planter.variables = variables if variables.is_a?(Hash)
|
14
|
-
Planter.config = template if template
|
16
|
+
# Planter.config = template if template
|
17
|
+
template ||= Planter.template
|
18
|
+
die('No template specified', :config) unless template
|
19
|
+
|
20
|
+
@config = Planter::Config.new
|
15
21
|
|
16
|
-
@basedir = File.join(Planter.base_dir, 'templates',
|
22
|
+
@basedir = File.join(Planter.base_dir, 'templates', @config.template)
|
17
23
|
@target = Planter.target || Dir.pwd
|
18
24
|
|
19
|
-
@git =
|
25
|
+
@git = @config.git_init || false
|
20
26
|
@debug = Planter.debug
|
21
|
-
@repo =
|
27
|
+
@repo = @config.repo || false
|
22
28
|
|
23
29
|
# Coerce any existing variables (like from the command line) to the types
|
24
30
|
# defined in configuration
|
25
31
|
coerced = {}
|
26
32
|
Planter.variables.each do |k, v|
|
27
|
-
cfg_var =
|
33
|
+
cfg_var = @config.variables.select { |var| k = var[:key] }
|
28
34
|
next unless cfg_var.count.positive?
|
29
35
|
|
30
36
|
var = cfg_var.first
|
@@ -34,7 +40,7 @@ module Planter
|
|
34
40
|
coerced.each { |k, v| Planter.variables[k] = v }
|
35
41
|
|
36
42
|
# Ask user for any variables not already defined
|
37
|
-
|
43
|
+
@config.variables.each do |var|
|
38
44
|
key = var[:key].to_var
|
39
45
|
next if Planter.variables.keys.include?(key)
|
40
46
|
|
@@ -46,7 +52,8 @@ module Planter
|
|
46
52
|
value: var[:value],
|
47
53
|
min: var[:min],
|
48
54
|
max: var[:max],
|
49
|
-
choices: var[:choices] || nil
|
55
|
+
choices: var[:choices] || nil,
|
56
|
+
date_format: var[:date_format] || nil
|
50
57
|
)
|
51
58
|
answer = q.ask
|
52
59
|
if answer.nil?
|
@@ -55,7 +62,7 @@ module Planter
|
|
55
62
|
answer = var[:default]
|
56
63
|
end
|
57
64
|
|
58
|
-
Planter.variables[key] = answer
|
65
|
+
Planter.variables[key] = answer.apply_all
|
59
66
|
end
|
60
67
|
|
61
68
|
git_pull if @repo
|
@@ -94,26 +101,26 @@ module Planter
|
|
94
101
|
def git_pull
|
95
102
|
Planter.spinner.update(title: 'Pulling git repo')
|
96
103
|
|
97
|
-
|
104
|
+
die('`git` executable not found', :git) unless TTY::Which.exist?('git')
|
98
105
|
|
99
106
|
pwd = Dir.pwd
|
100
107
|
@repo = expand_repo(@repo)
|
101
108
|
|
102
109
|
if File.exist?(repo_dir)
|
103
110
|
Dir.chdir(repo_dir)
|
104
|
-
|
111
|
+
die("Directory #{repo_dir} exists but is not git repo", :git) unless File.exist?('.git')
|
105
112
|
|
106
113
|
res = `git pull`
|
107
|
-
|
114
|
+
die("Error pulling #{@repo}:\n#{res}", :git) unless $?.success?
|
108
115
|
else
|
109
116
|
Dir.chdir(@basedir)
|
110
117
|
res = `git clone "#{@repo}" "#{repo_dir}"`
|
111
|
-
|
118
|
+
die("Error cloning #{@repo}:\n#{res}", :git) unless $?.success?
|
112
119
|
end
|
113
120
|
Dir.chdir(pwd)
|
114
121
|
@basedir = repo_dir
|
115
122
|
rescue StandardError => e
|
116
|
-
|
123
|
+
die("Error pulling #{@repo}:\n#{e.message}", :git)
|
117
124
|
end
|
118
125
|
|
119
126
|
##
|
@@ -139,7 +146,7 @@ module Planter
|
|
139
146
|
end
|
140
147
|
|
141
148
|
if @git
|
142
|
-
|
149
|
+
die('`git` executable not found', :git) unless TTY::Which.exist?('git')
|
143
150
|
|
144
151
|
Planter.spinner.update(title: 'Initializing git repo')
|
145
152
|
res = add_git
|
@@ -149,10 +156,10 @@ module Planter
|
|
149
156
|
end
|
150
157
|
end
|
151
158
|
|
152
|
-
if
|
159
|
+
if @config.script
|
153
160
|
Planter.spinner.update(title: 'Running script')
|
154
161
|
|
155
|
-
scripts =
|
162
|
+
scripts = @config.script
|
156
163
|
scripts = [scripts] if scripts.is_a?(String)
|
157
164
|
scripts.each do |script|
|
158
165
|
s = Planter::Script.new(@basedir, Dir.pwd, script)
|
@@ -184,7 +191,7 @@ module Planter
|
|
184
191
|
|
185
192
|
content = IO.read(file)
|
186
193
|
|
187
|
-
new_content = content.
|
194
|
+
new_content = content.apply_all
|
188
195
|
|
189
196
|
new_content.gsub!(%r{^.{.4}/?merge *.{,4}\n}, '') if new_content =~ /^.{.4}merge *\n/
|
190
197
|
|
data/lib/planter/prompt.rb
CHANGED
@@ -21,9 +21,10 @@ module Planter
|
|
21
21
|
@min = question[:min]&.to_f || 1.0
|
22
22
|
@max = question[:max]&.to_f || 10.0
|
23
23
|
@prompt = question[:prompt] || nil
|
24
|
-
@default = question[:default]
|
24
|
+
@default = question[:default]&.to_s&.apply_all || nil
|
25
25
|
@value = question[:value]
|
26
26
|
@choices = question[:choices] || []
|
27
|
+
@date_format = question[:date_format] || nil
|
27
28
|
@gum = false # TTY::Which.exist?('gum')
|
28
29
|
end
|
29
30
|
|
@@ -35,7 +36,7 @@ module Planter
|
|
35
36
|
def ask
|
36
37
|
return nil if @prompt.nil?
|
37
38
|
|
38
|
-
return @value.to_s.
|
39
|
+
return @value.to_s.apply_all.coerce(@type) if @value && @type != :date
|
39
40
|
|
40
41
|
res = case @type
|
41
42
|
when :choice
|
@@ -58,9 +59,9 @@ module Planter
|
|
58
59
|
read_line
|
59
60
|
end
|
60
61
|
Planter.notify("{dw}#{prompt} => {dy}#{res}{x}", :debug, newline: false)
|
61
|
-
res
|
62
|
+
res.to_s.apply_all
|
62
63
|
rescue TTY::Reader::InputInterrupt
|
63
|
-
|
64
|
+
die('Canceled')
|
64
65
|
end
|
65
66
|
|
66
67
|
private
|
@@ -73,7 +74,7 @@ module Planter
|
|
73
74
|
## @return [Number] numeric response
|
74
75
|
##
|
75
76
|
def read_number(integer: false)
|
76
|
-
default = @default ? " {
|
77
|
+
default = @default ? " {xw}[{xbw}#{@default}{xw}]" : ''
|
77
78
|
Planter.notify("{by}#{@prompt} {xc}({bw}#{@min}{xc}-{bw}#{@max}{xc})#{default}")
|
78
79
|
|
79
80
|
res = @gum ? read_number_gum : read_line_tty
|
@@ -95,15 +96,20 @@ module Planter
|
|
95
96
|
default = @value || @default
|
96
97
|
return nil unless default
|
97
98
|
|
99
|
+
if default =~ /'.*?'/
|
100
|
+
@date_format = default.match(/'(.*?)'/)[1].strip
|
101
|
+
default = default.gsub(/'.*?'/, '').strip
|
102
|
+
end
|
103
|
+
|
98
104
|
case default
|
99
105
|
when /^(no|ti)/
|
100
|
-
Time.now.strftime('%Y-%m-%d %H:%M')
|
106
|
+
Time.now.strftime(@date_format || '%Y-%m-%d %H:%M')
|
101
107
|
when /^(to|da)/
|
102
|
-
Time.now.strftime('%Y-%m-%d')
|
108
|
+
Time.now.strftime(@date_format || '%Y-%m-%d')
|
103
109
|
when /^%/
|
104
|
-
Time.now.strftime(
|
110
|
+
Time.now.strftime(default)
|
105
111
|
else
|
106
|
-
Chronic.parse(default).strftime('%Y-%m-%d')
|
112
|
+
Chronic.parse(default).strftime(@date_format || '%Y-%m-%d')
|
107
113
|
end
|
108
114
|
end
|
109
115
|
|
@@ -123,7 +129,7 @@ module Planter
|
|
123
129
|
line = @gum ? read_line_gum : read_line_tty
|
124
130
|
return default unless line
|
125
131
|
|
126
|
-
Chronic.parse(line).strftime('%Y-%m-%d')
|
132
|
+
Chronic.parse(line).strftime(@date_format || '%Y-%m-%d')
|
127
133
|
end
|
128
134
|
|
129
135
|
##
|
@@ -136,6 +142,8 @@ module Planter
|
|
136
142
|
## @return [String] the single-line response
|
137
143
|
##
|
138
144
|
def read_line(prompt: nil)
|
145
|
+
return @default if Planter.accept_defaults || ENV['PLANTER_DEBUG']
|
146
|
+
|
139
147
|
prompt ||= @prompt
|
140
148
|
default = @default ? " {bw}[#{@default}]" : ''
|
141
149
|
Planter.notify("{by}#{prompt}#{default}", newline: false)
|
@@ -234,7 +242,7 @@ module Planter
|
|
234
242
|
##
|
235
243
|
## Choose from an array of multiple choices. Letter surrounded in
|
236
244
|
## parenthesis becomes character for response. Only one letter should be
|
237
|
-
## specified and must be unique.
|
245
|
+
## specified per choice and must be unique.
|
238
246
|
##
|
239
247
|
## @param choices [Array] The choices
|
240
248
|
## @param prompt [String] The prompt
|
@@ -260,6 +268,8 @@ module Planter
|
|
260
268
|
values = choices.to_values.map(&:clean_value)
|
261
269
|
end
|
262
270
|
|
271
|
+
die('Choice(s) without selector, please edit config') unless keys.all?(&:has_selector?)
|
272
|
+
|
263
273
|
default = case default_response.to_s
|
264
274
|
when /^\d+$/
|
265
275
|
values[default.to_i]
|
@@ -307,6 +317,8 @@ module Planter
|
|
307
317
|
|
308
318
|
res = res.empty? ? default : res
|
309
319
|
|
320
|
+
return choice(choices, prompt, default_response: default_response) if res.nil? || res.empty?
|
321
|
+
|
310
322
|
if res.to_i.positive?
|
311
323
|
values[res.to_i - 1]
|
312
324
|
elsif res =~ /^[a-z]/ && keys&.option_index(res)
|
data/lib/planter/script.rb
CHANGED
@@ -14,12 +14,12 @@ module Planter
|
|
14
14
|
##
|
15
15
|
def initialize(template_dir, output_dir, script)
|
16
16
|
found = find_script(template_dir, script)
|
17
|
-
|
17
|
+
die("Script #{script} not found", :script) unless found
|
18
18
|
|
19
19
|
@script = found
|
20
20
|
make_executable
|
21
21
|
|
22
|
-
|
22
|
+
die("Output directory #{output_dir} not found", :script) unless File.directory?(output_dir)
|
23
23
|
|
24
24
|
@template_directory = template_dir
|
25
25
|
@directory = output_dir
|
@@ -63,7 +63,7 @@ module Planter
|
|
63
63
|
stdout, stderr, status = Open3.capture3(@script, @template_directory, @directory)
|
64
64
|
Planter.notify("STDOUT:\n#{stdout}", :debug) unless stdout.empty?
|
65
65
|
Planter.notify("STDERR:\n#{stderr}", :debug) unless stderr.empty?
|
66
|
-
|
66
|
+
die("Error running #{@script}", :script) unless status.success?
|
67
67
|
|
68
68
|
true
|
69
69
|
end
|
data/lib/planter/string.rb
CHANGED
@@ -138,11 +138,14 @@ module Planter
|
|
138
138
|
MOD_RX = '(?<mod>
|
139
139
|
(?::
|
140
140
|
(
|
141
|
-
l(?:ow(?:er)?)?)?|
|
142
|
-
|
141
|
+
l(?:ow(?:er(case)?)?)?)?|
|
142
|
+
d(?:own(?:case)?)?|
|
143
|
+
u(?:p(?:per(case)?)?)?|upcase|
|
143
144
|
c(?:ap(?:ital(?:ize)?)?)?|
|
144
145
|
t(?:itle)?|
|
145
146
|
snake|camel|slug|
|
147
|
+
fl|first_letter|
|
148
|
+
fw|first_word|
|
146
149
|
f(?:ile(?:name)?
|
147
150
|
)?
|
148
151
|
)*
|
@@ -172,7 +175,7 @@ module Planter
|
|
172
175
|
m['default'].apply_var_names
|
173
176
|
else
|
174
177
|
# Retrieve the default value for the variable from the configuration
|
175
|
-
vars = Planter.config
|
178
|
+
vars = Planter.config.variables.filter { |v| v[:key] == m['varname'] }
|
176
179
|
default = vars.first[:default] if vars.count.positive?
|
177
180
|
if default.nil?
|
178
181
|
m[0]
|
@@ -204,8 +207,7 @@ module Planter
|
|
204
207
|
def apply_logic(variables = nil)
|
205
208
|
variables = variables.nil? ? Planter.variables : variables
|
206
209
|
|
207
|
-
gsub(/%%if .*?%%.*?%%end(if)?%%/mi) do |construct|
|
208
|
-
res = false
|
210
|
+
gsub(/%%if .*?%%.*?%%end( ?if)?%%/mi) do |construct|
|
209
211
|
# Get the condition and the content
|
210
212
|
output = construct.match(/%%else%%(.*?)%%end/m) ? Regexp.last_match(1) : ''
|
211
213
|
|
@@ -213,72 +215,8 @@ module Planter
|
|
213
215
|
/%%(?<statement>(?:els(?:e )?)?if) (?<condition>.*?)%%(?<content>.*?)(?=%%)/mi).map do
|
214
216
|
Regexp.last_match
|
215
217
|
end
|
216
|
-
conditions.each do |condition|
|
217
|
-
variable, operator, value = condition['condition'].split(/ +/, 3)
|
218
|
-
value.strip_quotes!
|
219
|
-
variable = variable.to_var
|
220
|
-
negate = false
|
221
|
-
if operator =~ /^!/
|
222
|
-
operator = operator[1..-1]
|
223
|
-
negate = true
|
224
|
-
end
|
225
|
-
operator = case operator
|
226
|
-
when /^={1,2}/
|
227
|
-
:equal
|
228
|
-
when /^=~/
|
229
|
-
:matches_regex
|
230
|
-
when /\*=/
|
231
|
-
:contains
|
232
|
-
when /\^=/
|
233
|
-
:starts_with
|
234
|
-
when /\$=/
|
235
|
-
:ends_with
|
236
|
-
when />/
|
237
|
-
:greater_than
|
238
|
-
when /</
|
239
|
-
:less_than
|
240
|
-
when />=/
|
241
|
-
:greater_than_or_equal
|
242
|
-
when /<=/
|
243
|
-
:less_than_or_equal
|
244
|
-
else
|
245
|
-
:equal
|
246
|
-
end
|
247
|
-
|
248
|
-
comp = variables[variable.to_var].to_s
|
249
|
-
|
250
|
-
res = case operator
|
251
|
-
when :equal
|
252
|
-
comp =~ /^#{value}$/i
|
253
|
-
when :matches_regex
|
254
|
-
comp =~ Regexp.new(value.gsub(%r{^/|/$}, ''))
|
255
|
-
when :contains
|
256
|
-
comp =~ /#{value}/i
|
257
|
-
when :starts_with
|
258
|
-
comp =~ /^#{value}/i
|
259
|
-
when :ends_with
|
260
|
-
comp =~ /#{value}$/i
|
261
|
-
when :greater_than
|
262
|
-
comp > value.to_f
|
263
|
-
when :less_than
|
264
|
-
comp < value.to_f
|
265
|
-
when :greater_than_or_equal
|
266
|
-
comp >= value.to_f
|
267
|
-
when :less_than_or_equal
|
268
|
-
comp <= value.to_f
|
269
|
-
else
|
270
|
-
false
|
271
|
-
end
|
272
|
-
res = !res if negate
|
273
|
-
|
274
|
-
next unless res
|
275
|
-
|
276
|
-
Planter.notify("Condition matched: #{comp} #{negate ? 'not ' : ''}#{operator} #{value}", :debug)
|
277
|
-
output = condition['content']
|
278
|
-
break
|
279
|
-
end
|
280
218
|
|
281
|
-
output
|
219
|
+
apply_conditions(conditions, variables, output)
|
282
220
|
end
|
283
221
|
end
|
284
222
|
|
@@ -287,6 +225,118 @@ module Planter
|
|
287
225
|
replace apply_logic(variables)
|
288
226
|
end
|
289
227
|
|
228
|
+
##
|
229
|
+
## Apply operator logic to a string. Operators are defined as
|
230
|
+
## :copy, :overwrite, :ignore, or :merge. Logic can be if/else
|
231
|
+
## constructs or inline operators.
|
232
|
+
##
|
233
|
+
## @example "var = 1; if var == 1:copy; else: ignore" #=> :copy
|
234
|
+
## @example "var = 2; copy if var == 1 else ignore" #=> :ignore
|
235
|
+
##
|
236
|
+
## @param variables [Hash] Hash of variables (default: Planter.variables)
|
237
|
+
##
|
238
|
+
def apply_operator_logic(variables = nil)
|
239
|
+
variables = variables.nil? ? Planter.variables : variables
|
240
|
+
op_rx = ' *(?<content>c(?:opy)?|o(?:ver(?:write)?)?|i(?:gnore)?|m(?:erge)?)? *'
|
241
|
+
|
242
|
+
strip.gsub(/^if .*?(?:end(?: ?if)?|$)/mi) do |construct|
|
243
|
+
# Get the condition and the content
|
244
|
+
output = construct.match(/else:#{op_rx}/m) ? Regexp.last_match(1) : ''
|
245
|
+
|
246
|
+
conditions = construct.to_enum(:scan,
|
247
|
+
/(?<statement>(?:els(?:e )?)?if) +(?<condition>.*?):#{op_rx}(?=;|$)/mi).map do
|
248
|
+
Regexp.last_match
|
249
|
+
end
|
250
|
+
|
251
|
+
apply_conditions(conditions, variables, output)
|
252
|
+
end.gsub(/^#{op_rx} +if .*?(end( ?if)?|$)/mi) do |construct|
|
253
|
+
# Get the condition and the content
|
254
|
+
output = construct.match(/else[; ]+(#{op_rx})/m) ? Regexp.last_match(1) : :ignore
|
255
|
+
condition = construct.match(/^#{op_rx}(?<statement>if) +(?<condition>.*?)(?=;|$)/mi)
|
256
|
+
|
257
|
+
apply_conditions([condition], variables, output)
|
258
|
+
end.normalize_operator
|
259
|
+
end
|
260
|
+
|
261
|
+
##
|
262
|
+
## Apply conditions
|
263
|
+
##
|
264
|
+
## @param conditions [Array<MatchData>] Array of conditions ['statement', 'condition', 'content']
|
265
|
+
## @param variables [Hash] Hash of variables
|
266
|
+
## @param output [String] Output string
|
267
|
+
##
|
268
|
+
## @return [String] Output string
|
269
|
+
##
|
270
|
+
def apply_conditions(conditions, variables, output)
|
271
|
+
res = false
|
272
|
+
conditions.each do |condition|
|
273
|
+
variable, operator, value = condition['condition'].split(/ +/, 3)
|
274
|
+
value.strip_quotes!
|
275
|
+
variable = variable.to_var
|
276
|
+
negate = false
|
277
|
+
if operator =~ /^!/
|
278
|
+
operator = operator[1..-1]
|
279
|
+
negate = true
|
280
|
+
end
|
281
|
+
operator = case operator
|
282
|
+
when /^={1,2}/
|
283
|
+
:equal
|
284
|
+
when /^=~/
|
285
|
+
:matches_regex
|
286
|
+
when /\*=/
|
287
|
+
:contains
|
288
|
+
when /\^=/
|
289
|
+
:starts_with
|
290
|
+
when /\$=/
|
291
|
+
:ends_with
|
292
|
+
when />/
|
293
|
+
:greater_than
|
294
|
+
when /</
|
295
|
+
:less_than
|
296
|
+
when />=/
|
297
|
+
:greater_than_or_equal
|
298
|
+
when /<=/
|
299
|
+
:less_than_or_equal
|
300
|
+
else
|
301
|
+
:equal
|
302
|
+
end
|
303
|
+
|
304
|
+
comp = variables[variable.to_var].to_s
|
305
|
+
|
306
|
+
res = case operator
|
307
|
+
when :equal
|
308
|
+
comp =~ /^#{value}$/i
|
309
|
+
when :matches_regex
|
310
|
+
comp =~ Regexp.new(value.gsub(%r{^/|/$}, ''))
|
311
|
+
when :contains
|
312
|
+
comp =~ /#{value}/i
|
313
|
+
when :starts_with
|
314
|
+
comp =~ /^#{value}/i
|
315
|
+
when :ends_with
|
316
|
+
comp =~ /#{value}$/i
|
317
|
+
when :greater_than
|
318
|
+
comp > value.to_f
|
319
|
+
when :less_than
|
320
|
+
comp < value.to_f
|
321
|
+
when :greater_than_or_equal
|
322
|
+
comp >= value.to_f
|
323
|
+
when :less_than_or_equal
|
324
|
+
comp <= value.to_f
|
325
|
+
else
|
326
|
+
false
|
327
|
+
end
|
328
|
+
res = res ? true : false
|
329
|
+
res = !res if negate
|
330
|
+
|
331
|
+
next unless res
|
332
|
+
|
333
|
+
Planter.notify("Condition matched: #{comp} #{negate ? 'not ' : ''}#{operator} #{value}", :debug)
|
334
|
+
output = condition['content']
|
335
|
+
break
|
336
|
+
end
|
337
|
+
output
|
338
|
+
end
|
339
|
+
|
290
340
|
##
|
291
341
|
## Apply key/value substitutions to a string. Variables are represented as
|
292
342
|
## %%key%%, and the hash passed to the function is { key: value }
|
@@ -326,6 +376,8 @@ module Planter
|
|
326
376
|
if m['mod']
|
327
377
|
mods = m['mod']&.split(/:/)
|
328
378
|
mods&.each do |mod|
|
379
|
+
next if mod.nil? || mod.empty?
|
380
|
+
|
329
381
|
v = v.apply_mod(mod.normalize_mod)
|
330
382
|
end
|
331
383
|
end
|
@@ -369,13 +421,20 @@ module Planter
|
|
369
421
|
end
|
370
422
|
|
371
423
|
##
|
372
|
-
## Apply
|
424
|
+
## Apply all logic, variables, and regexes to a string
|
425
|
+
##
|
426
|
+
def apply_all
|
427
|
+
apply_logic.apply_variables.apply_regexes
|
428
|
+
end
|
429
|
+
|
430
|
+
##
|
431
|
+
## Apply regex replacements from Planter.config[:replacements]
|
373
432
|
##
|
374
433
|
## @return [String] string with regexes applied
|
375
434
|
##
|
376
435
|
def apply_regexes(regexes = nil)
|
377
436
|
content = dup.clean_encode
|
378
|
-
regexes = regexes.nil? && Planter.config.key?(:replacements) ? Planter.config
|
437
|
+
regexes = regexes.nil? && Planter.config.key?(:replacements) ? Planter.config.replacements : regexes
|
379
438
|
|
380
439
|
return self unless regexes
|
381
440
|
|
@@ -455,6 +514,10 @@ module Planter
|
|
455
514
|
snake_case
|
456
515
|
when :camel_case
|
457
516
|
camel_case
|
517
|
+
when :first_letter
|
518
|
+
split('')[0]
|
519
|
+
when :first_word
|
520
|
+
split(/[ !,?;:]+/)[0]
|
458
521
|
else
|
459
522
|
self
|
460
523
|
end
|
@@ -481,7 +544,7 @@ module Planter
|
|
481
544
|
##
|
482
545
|
def normalize_mod
|
483
546
|
case self
|
484
|
-
when /^(
|
547
|
+
when /^(file|slug)/
|
485
548
|
:slug
|
486
549
|
when /^cam/
|
487
550
|
:camel_case
|
@@ -489,10 +552,14 @@ module Planter
|
|
489
552
|
:snake_case
|
490
553
|
when /^u/
|
491
554
|
:uppercase
|
492
|
-
when /^
|
555
|
+
when /^[ld]/
|
493
556
|
:lowercase
|
494
557
|
when /^[ct]/
|
495
558
|
:title_case
|
559
|
+
when /^(fl|first_letter)/
|
560
|
+
:first_letter
|
561
|
+
when /^(fw|first_word)/
|
562
|
+
:first_word
|
496
563
|
end
|
497
564
|
end
|
498
565
|
|
@@ -622,5 +689,14 @@ module Planter
|
|
622
689
|
gsub(/\((.)\)/, '{dw}({xbw}\1{dw}){xw}')
|
623
690
|
end
|
624
691
|
end
|
692
|
+
|
693
|
+
#
|
694
|
+
# Test if a string has a parenthetical selector
|
695
|
+
#
|
696
|
+
# @return [Boolean] has selector
|
697
|
+
#
|
698
|
+
def has_selector?
|
699
|
+
self =~ /\(.\)/ ? true : false
|
700
|
+
end
|
625
701
|
end
|
626
702
|
end
|
data/lib/planter/tag.rb
CHANGED
@@ -1,8 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Planter
|
4
|
+
#
|
5
|
+
# File tagging module
|
6
|
+
#
|
7
|
+
# @author Brett Terpstra <me@brettterpstra.com>
|
8
|
+
#
|
4
9
|
module Tag
|
10
|
+
# File tagging class
|
5
11
|
class << self
|
12
|
+
#
|
13
|
+
# Set tags on target file.
|
14
|
+
#
|
15
|
+
# @param target [String] path to target file
|
16
|
+
# @param tags [Array] Array of tags to set
|
17
|
+
#
|
18
|
+
# @return [Boolean] success
|
19
|
+
#
|
6
20
|
def set(target, tags)
|
7
21
|
return false unless TTY::Which.exist?('xattr')
|
8
22
|
|
@@ -36,6 +50,13 @@ module Planter
|
|
36
50
|
res
|
37
51
|
end
|
38
52
|
|
53
|
+
#
|
54
|
+
# Get tags on target file.
|
55
|
+
#
|
56
|
+
# @param target [String] target file path
|
57
|
+
#
|
58
|
+
# @return [Array] Array of tags
|
59
|
+
#
|
39
60
|
def get(target)
|
40
61
|
return false unless TTY::Which.exist?('xattr')
|
41
62
|
|
@@ -49,6 +70,14 @@ module Planter
|
|
49
70
|
tags
|
50
71
|
end
|
51
72
|
|
73
|
+
#
|
74
|
+
# Copy tags from one file to another.
|
75
|
+
#
|
76
|
+
# @param source [String] path to source file
|
77
|
+
# @param target [String] path to target file
|
78
|
+
#
|
79
|
+
# @return [Boolean] success
|
80
|
+
#
|
52
81
|
def copy(source, target)
|
53
82
|
return false unless TTY::Which.exist?('xattr')
|
54
83
|
|
@@ -67,6 +96,15 @@ module Planter
|
|
67
96
|
|
68
97
|
private
|
69
98
|
|
99
|
+
#
|
100
|
+
# Set tags on target file.
|
101
|
+
#
|
102
|
+
# @param target [String] file path
|
103
|
+
# @param tags [Array] Array of tags
|
104
|
+
#
|
105
|
+
# @return [Boolean] success
|
106
|
+
#
|
107
|
+
# @api private
|
70
108
|
def set_tags(target, tags)
|
71
109
|
return false unless TTY::Which.exist?('xattr')
|
72
110
|
|
data/lib/planter/version.rb
CHANGED