planter-cli 3.0.4 → 3.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.irbrc +2 -1
- data/.yardopts +1 -0
- data/CHANGELOG.md +20 -0
- data/README.md +131 -45
- data/bin/plant +5 -4
- 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 +131 -45
- 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