Skip to content

Instantly share code, notes, and snippets.

@toddnestor
Created May 3, 2017 22:20
Show Gist options
  • Save toddnestor/392ea5ff194e0b0d74cf6682c827a366 to your computer and use it in GitHub Desktop.
Save toddnestor/392ea5ff194e0b0d74cf6682c827a366 to your computer and use it in GitHub Desktop.
class for extracting arguments from a string
# This class is solely used for extracting arguments from a string
# It is used to process the arguments input to template_methods in the CMS content areas
# It handles arguments that are comma separated, inside or outside of quotes
# Like normal arguments to a programming function if something is inside a quote it will
# all be part of the same argument and commas inside of quotes are part of that argument
# rather than used to separate it from another argument. It also takes into account backslashes
# so 'I\'m an argument' will properly be processed
#
# For example link("http://google.com", 'Google is fun to use, really it is')
# It will result in the arguments:
# [
# "http://google.com",
# 'Google is fun to use, really it is, isn\'t it?'
# ]
class TemplateMethodArguments
def self.extract(str)
new(str).extract
end
def initialize(str)
@str = strip_parens(str)
end
def extract
@quotation_start = nil
@args = []
@current_arg = ''
@str.each_char.with_index do |char, i|
if @quotation_start.nil?
handle_non_quoted_argument(char, i)
else
handle_quoted_argument(char, i)
end
end
add_current_arg
@args
end
private
def strip_parens(str)
str = str.strip
str = str[1..-1] if str[0] == '('
str = str[0..-2] if str[-1] == ')'
str
end
def handle_non_quoted_argument(char, i)
if non_escaped_quote?(char, i)
begin_quoted_argument(char)
else
handle_non_quoted_char(char, i)
end
end
def handle_non_quoted_char(char, i)
if char == ','
add_current_arg(strip_arg: true)
elsif char != '\\' || escaped_char?(i)
@current_arg << char
end
end
def begin_quoted_argument(char)
@current_arg = ''
@quotation_start = char
end
def end_quoted_argument
add_current_arg(add_empty: true)
@quotation_start = nil
end
def handle_quoted_argument(char, i)
if char == @quotation_start && non_escaped_char?(i)
end_quoted_argument
elsif char != '\\' || escaped_char?(i)
@current_arg << char
end
end
def add_current_arg(strip_arg: false, add_empty: false)
@current_arg = @current_arg.strip if strip_arg
@args << @current_arg if @current_arg.present? || add_empty
@current_arg = ''
end
def non_escaped_quote?(char, i)
['\'', '"'].include?(char) && non_escaped_char?(i)
end
def non_escaped_char?(i)
i.zero? || @str[i - 1] != '\\'
end
def escaped_char?(i)
!i.zero? && @str[i - 1] == '\\'
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment