lib/planter/string.rb in planter-cli-3.0.4 vs lib/planter/string.rb in planter-cli-3.0.5
- old
+ new
@@ -136,15 +136,18 @@
# @return [String] Regular expression for matching variable modifiers
MOD_RX = '(?<mod>
(?::
(
- l(?:ow(?:er)?)?)?|
- u(?:p(?:per)?)?|
+ l(?:ow(?:er(case)?)?)?)?|
+ d(?:own(?:case)?)?|
+ u(?:p(?:per(case)?)?)?|upcase|
c(?:ap(?:ital(?:ize)?)?)?|
t(?:itle)?|
snake|camel|slug|
+ fl|first_letter|
+ fw|first_word|
f(?:ile(?:name)?
)?
)*
)'
# @return [String] regular expression string for default values
@@ -170,11 +173,11 @@
if !variables.key?(m['varname'].to_var)
# If the variable is not present, use the default value from the match
m['default'].apply_var_names
else
# Retrieve the default value for the variable from the configuration
- vars = Planter.config[:variables].filter { |v| v[:key] == m['varname'] }
+ vars = Planter.config.variables.filter { |v| v[:key] == m['varname'] }
default = vars.first[:default] if vars.count.positive?
if default.nil?
m[0]
elsif variables[m['varname'].to_var] == default
# If the variable's value matches the default value, use the default value from the match
@@ -202,91 +205,138 @@
## @param variables [Hash] Hash of variables to apply
##
def apply_logic(variables = nil)
variables = variables.nil? ? Planter.variables : variables
- gsub(/%%if .*?%%.*?%%end(if)?%%/mi) do |construct|
- res = false
+ gsub(/%%if .*?%%.*?%%end( ?if)?%%/mi) do |construct|
# Get the condition and the content
output = construct.match(/%%else%%(.*?)%%end/m) ? Regexp.last_match(1) : ''
conditions = construct.to_enum(:scan,
/%%(?<statement>(?:els(?:e )?)?if) (?<condition>.*?)%%(?<content>.*?)(?=%%)/mi).map do
Regexp.last_match
end
- conditions.each do |condition|
- variable, operator, value = condition['condition'].split(/ +/, 3)
- value.strip_quotes!
- variable = variable.to_var
- negate = false
- if operator =~ /^!/
- operator = operator[1..-1]
- negate = true
- end
- operator = case operator
- when /^={1,2}/
- :equal
- when /^=~/
- :matches_regex
- when /\*=/
- :contains
- when /\^=/
- :starts_with
- when /\$=/
- :ends_with
- when />/
- :greater_than
- when /</
- :less_than
- when />=/
- :greater_than_or_equal
- when /<=/
- :less_than_or_equal
- else
- :equal
- end
- comp = variables[variable.to_var].to_s
+ apply_conditions(conditions, variables, output)
+ end
+ end
- res = case operator
- when :equal
- comp =~ /^#{value}$/i
- when :matches_regex
- comp =~ Regexp.new(value.gsub(%r{^/|/$}, ''))
- when :contains
- comp =~ /#{value}/i
- when :starts_with
- comp =~ /^#{value}/i
- when :ends_with
- comp =~ /#{value}$/i
- when :greater_than
- comp > value.to_f
- when :less_than
- comp < value.to_f
- when :greater_than_or_equal
- comp >= value.to_f
- when :less_than_or_equal
- comp <= value.to_f
- else
- false
- end
- res = !res if negate
+ ## Destructive version of #apply_logic
+ def apply_logic!(variables)
+ replace apply_logic(variables)
+ end
- next unless res
+ ##
+ ## Apply operator logic to a string. Operators are defined as
+ ## :copy, :overwrite, :ignore, or :merge. Logic can be if/else
+ ## constructs or inline operators.
+ ##
+ ## @example "var = 1; if var == 1:copy; else: ignore" #=> :copy
+ ## @example "var = 2; copy if var == 1 else ignore" #=> :ignore
+ ##
+ ## @param variables [Hash] Hash of variables (default: Planter.variables)
+ ##
+ def apply_operator_logic(variables = nil)
+ variables = variables.nil? ? Planter.variables : variables
+ op_rx = ' *(?<content>c(?:opy)?|o(?:ver(?:write)?)?|i(?:gnore)?|m(?:erge)?)? *'
- Planter.notify("Condition matched: #{comp} #{negate ? 'not ' : ''}#{operator} #{value}", :debug)
- output = condition['content']
- break
+ strip.gsub(/^if .*?(?:end(?: ?if)?|$)/mi) do |construct|
+ # Get the condition and the content
+ output = construct.match(/else:#{op_rx}/m) ? Regexp.last_match(1) : ''
+
+ conditions = construct.to_enum(:scan,
+ /(?<statement>(?:els(?:e )?)?if) +(?<condition>.*?):#{op_rx}(?=;|$)/mi).map do
+ Regexp.last_match
end
- output
- end
+ apply_conditions(conditions, variables, output)
+ end.gsub(/^#{op_rx} +if .*?(end( ?if)?|$)/mi) do |construct|
+ # Get the condition and the content
+ output = construct.match(/else[; ]+(#{op_rx})/m) ? Regexp.last_match(1) : :ignore
+ condition = construct.match(/^#{op_rx}(?<statement>if) +(?<condition>.*?)(?=;|$)/mi)
+
+ apply_conditions([condition], variables, output)
+ end.normalize_operator
end
- ## Destructive version of #apply_logic
- def apply_logic!(variables)
- replace apply_logic(variables)
+ ##
+ ## Apply conditions
+ ##
+ ## @param conditions [Array<MatchData>] Array of conditions ['statement', 'condition', 'content']
+ ## @param variables [Hash] Hash of variables
+ ## @param output [String] Output string
+ ##
+ ## @return [String] Output string
+ ##
+ def apply_conditions(conditions, variables, output)
+ res = false
+ conditions.each do |condition|
+ variable, operator, value = condition['condition'].split(/ +/, 3)
+ value.strip_quotes!
+ variable = variable.to_var
+ negate = false
+ if operator =~ /^!/
+ operator = operator[1..-1]
+ negate = true
+ end
+ operator = case operator
+ when /^={1,2}/
+ :equal
+ when /^=~/
+ :matches_regex
+ when /\*=/
+ :contains
+ when /\^=/
+ :starts_with
+ when /\$=/
+ :ends_with
+ when />/
+ :greater_than
+ when /</
+ :less_than
+ when />=/
+ :greater_than_or_equal
+ when /<=/
+ :less_than_or_equal
+ else
+ :equal
+ end
+
+ comp = variables[variable.to_var].to_s
+
+ res = case operator
+ when :equal
+ comp =~ /^#{value}$/i
+ when :matches_regex
+ comp =~ Regexp.new(value.gsub(%r{^/|/$}, ''))
+ when :contains
+ comp =~ /#{value}/i
+ when :starts_with
+ comp =~ /^#{value}/i
+ when :ends_with
+ comp =~ /#{value}$/i
+ when :greater_than
+ comp > value.to_f
+ when :less_than
+ comp < value.to_f
+ when :greater_than_or_equal
+ comp >= value.to_f
+ when :less_than_or_equal
+ comp <= value.to_f
+ else
+ false
+ end
+ res = res ? true : false
+ res = !res if negate
+
+ next unless res
+
+ Planter.notify("Condition matched: #{comp} #{negate ? 'not ' : ''}#{operator} #{value}", :debug)
+ output = condition['content']
+ break
+ end
+ output
end
##
## Apply key/value substitutions to a string. Variables are represented as
## %%key%%, and the hash passed to the function is { key: value }
@@ -324,10 +374,12 @@
m = Regexp.last_match
if m['mod']
mods = m['mod']&.split(/:/)
mods&.each do |mod|
+ next if mod.nil? || mod.empty?
+
v = v.apply_mod(mod.normalize_mod)
end
end
v
end
@@ -367,17 +419,24 @@
end
content
end
##
- ## Apply regex replacements from @config[:replacements]
+ ## Apply all logic, variables, and regexes to a string
##
+ def apply_all
+ apply_logic.apply_variables.apply_regexes
+ end
+
+ ##
+ ## Apply regex replacements from Planter.config[:replacements]
+ ##
## @return [String] string with regexes applied
##
def apply_regexes(regexes = nil)
content = dup.clean_encode
- regexes = regexes.nil? && Planter.config.key?(:replacements) ? Planter.config[:replacements] : regexes
+ regexes = regexes.nil? && Planter.config.key?(:replacements) ? Planter.config.replacements : regexes
return self unless regexes
regexes.stringify_keys.each do |pattern, replacement|
pattern = Regexp.new(pattern) unless pattern.is_a?(Regexp)
@@ -453,10 +512,14 @@
upcase
when :snake_case
snake_case
when :camel_case
camel_case
+ when :first_letter
+ split('')[0]
+ when :first_word
+ split(/[ !,?;:]+/)[0]
else
self
end
end
@@ -479,22 +542,26 @@
##
## @return [Symbol] symbolized modifier
##
def normalize_mod
case self
- when /^(f|slug)/
+ when /^(file|slug)/
:slug
when /^cam/
:camel_case
when /^s/
:snake_case
when /^u/
:uppercase
- when /^l/
+ when /^[ld]/
:lowercase
when /^[ct]/
:title_case
+ when /^(fl|first_letter)/
+ :first_letter
+ when /^(fw|first_word)/
+ :first_word
end
end
##
## Convert operator string to symbol
@@ -619,8 +686,17 @@
if default
gsub(/\((#{default})\)/, '{dw}({xbc}\1{dw}){xw}').gsub(/\((.)\)/, '{dw}({xbw}\1{dw}){xw}')
else
gsub(/\((.)\)/, '{dw}({xbw}\1{dw}){xw}')
end
+ end
+
+ #
+ # Test if a string has a parenthetical selector
+ #
+ # @return [Boolean] has selector
+ #
+ def has_selector?
+ self =~ /\(.\)/ ? true : false
end
end
end