Поискав в интернете способ распарсивания командной строки, решил таки пополнить список самодельщиков и любителей парсеров. Возможно кому-нибудь пригодится данный код.
Итак, задача стояла следующая: необходимо распарсить набор параметров адресной строки URL, с возможностью получать массивы. Поискав в интернете решение этой задачи, решил, что будет быстрее сделать самому то, что нужно.
def params_to_hash(_params="") return {} if _params.grep(/\=/).blank? result = {} _params = (URI.parse(_params).query || "") unless _params.grep(/\?/).blank? l = lambda {|x, a| a[0]=="" ? (a[1].is_a?(Array) ? (x = x || []) << l.call(x, a[1]) : CGI.unescape(a[1])) : (x = x || {}).merge({a[0].to_sym => a[1].is_a?(Array) ? l.call(x[a[0].to_sym], a[1]) : CGI.unescape(a[1])}) } _params.split("&").each do |item| next if item.size == 0 item += " " if item.split(/\=/).size < 2 k = item.split(/\]\[|\[|\]|\=/).reverse k[0] = "" if k[0] == " " q = k.inject(nil) {|r, i| r = (r.nil? ? i : [i, r]) } result = l.call(result, q) end return result end
Основную итерацию разборки параметра можно поделить условно на две части.
Подготовка строки параметра для рекурсивной обработки. Например, параметр вида «g[b][e][]=2» преобразуется в массив основным свойством которого является вложенность массивов размерность которых не превышает два элемента «[»g«, [»b«, [»e«, [»«, [»«, „2“]]]]]». Пустые строки в данном наборе расцениваются как признак массива «[]» и знак равно «=».
Пример подготовки массива для параметра с конечным значением типа массив «[]»
>> k = "g[b][e][]=2".split(/\]\[|\[|\]|\=/).reverse => ["2", "", "", "e", "b", "g"] >> q = k.inject(nil) {|r, i| r = (r.nil? ? i : [i, r]) } => ["g", ["b", ["e", ["", ["", "2"]]]]]
Пример подготовки массива для параметра с конечным значением типа строка или число «…»
>> k = "g[b][e]=2".split(/\]\[|\[|\]|\=/).reverse => ["2", "", "e", "b", "g"] >> q = k.inject(nil) {|r, i| r = (r.nil? ? i : [i, r]) } => ["g", ["b", ["e", ["", "2"]]]]
Последующая обработка массива выполняется рекуррентной лямбда-функцией. В качестве параметров эта функция принимает частично заполненный хэш параметров и массив. Лямбда функция дополняет или создает заново во входном хэше параметр на основе цепочки заложенной в массиве. Полагаю, глядя на массив, несложно будет понять, как работает лямбда функция.
Данная функция парсирует параметры вида «g[b][e][]=1&g[b][e][]=2&g[b][e][]=34&g[b][c]=d», но, увы, она не расчитана для парсирования массива сложных объектов, например, «g[][b][e][]=expression». Массив для этой функции может быть только конечным значением.
Пример работы функции
>> h = "g[b][e][]=1&g[b][e][]=2&g[b][e][]=34&g[b][c]=d" => "g[b][e][]=1&g[b][e][]=2&g[b][e][]=34&g[b][c]=d" >> params_to_hash(h) => {:g=>{:b=>{:c=>"d", :e=>["1", "2", "34"]}}}
Любителям dry-кода предлагаю вносить поправки 🙂