Использование значений массива в качестве ключей ha sh для создания вложенных хэшей в Ruby - PullRequest
1 голос
/ 21 марта 2020

Фон

У меня есть каталог файлов. Большинство из них .patch файлы, хотя некоторые из них нет. Для каждого файла патча мне нужно отсканировать первую строку, которая всегда является строкой, и извлечь часть этой строки. С комбинацией имени каждого файла, этой части каждой первой строки и уникального идентификатора для каждого файла мне нужно создать ха sh, который я затем преобразую в json и запишу в файл.

Вот примеры:

Каталог файлов (пример)

|__ .gitkeep
|__ pmet-add-install-module-timings.patch
|__ pmet-change-sample-data-load-order.patch
|__ pmet-stop-catching-sample-data-errrors-during-install.patch
|__ pmet-fix-admin-label-word-breaking.patch
|__ pmet-declare-shipping-factory-for-compilation.patch.disabled

...

Примеры первой строки

Имя файла: pmet-add-install-module-timings.patch

Первая строка: diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php

Имя файла: pmet-change-sample-data-load-order.patch

Первая строка: diff --git a/vendor/magento/module-sample-data/etc/module.xml b/vendor/magento/module-sample-data/etc/module.xml

Имя файла: pmet-stop-catching-sample-data-errrors-during-install.patch

Первая строка: diff --git a/vendor/magento/framework/Setup/SampleData/Executor.php b/vendor/magento/framework/Setup/SampleData/Executor.php

Имя файла: pmet-fix-admin-label-word-breaking.patch

Первая строка: diff --git a/vendor/magento/theme-adminhtml-backend/web/css/styles-old.less b/vendor/magento/theme-adminhtml-backend/web/css/styles-old.less

JSON Пример файла

{
    "patches": {
        "magento/magento2-base": {
            "Patch 1": "m2-hotfixes/pmet-add-install-module-timings.patch"
        },
        "magento/module-sample-data": {
            "Patch 2": "m2-hotfixes/pmet-change-sample-data-load-order.patch"
        },
        "magento/theme-adminhtml-backend": {
            "Patch 3": "m2-hotfixes/pmet-fix-admin-label-word-breaking.patch"
        },
        "magento/framework": {
            "Patch 4": "m2-hotfixes/pmet-stop-catching-sample-data-errrors-during-install.patch"
        }
    }
}

Решение Пока что scrape.rb

Вот код целиком. Ниже я разберу его ниже:

files_hash = Hash.new
modules = Array.new
data_hash = {
    patches: {}
}
files = Dir["*.patch"]
files.each do |file|
    files_hash.store(files.index(file), file)
end
files_hash.each do |key, file|
    value = File.open(file, &:readline).split('/')[3]
    if value.match(/module-/) || value.match(/theme-/)
        result = "magento/#{value}"
    else
        result = "magento2-base"
    end
    modules << result
    modules.each do |val|
        data_hash[:patches][val][key] = "m2-hotfixes/#{file}"
    end
end
print data_hash

Прежде чем высветить проблему, мне нужно сначала подробно рассказать, что я сделал для достижения желаемого конечного результата:

Сначала я установил пустые файлы ha sh, массив модулей и данные ha sh:

files_hash = Hash.new
modules = Array.new
data_hash = {
    patches: {}
}

Затем я сканирую каталог файлов исправлений на наличие .patch файлов и сохраняю их в файлах ha sh со своими ключами. (Я полагаю, что я могу использовать ключи в качестве меток патчей в файле JSON):

files = Dir["*.patch"]
files.each do |file|
    files_hash.store(files.index(file), file)
end

Далее я использую файл ha sh для чтения первой строки каждого файла патчей. Я заметил в файлах патчей паттерн, который, по моему мнению, будет надежным: каждый файл имеет magento/module-name, magento/theme-name или что-то еще. В случаях module-name и theme-name будет использоваться синтаксис magento/#{value}. В случае "что-то еще" будет использоваться magento/magento2-base:

files_hash.each do |key, file|
    value = File.open(file, &:readline).split('/')[3]
    if value.match(/module-/) || value.match(/theme-/)
        result = "magento/#{value}"
    else
        result = "magento2-base"
    end
    modules << result
...

Это не самое лучшее решение (что, если структура diff изменится?), Но пока оно работает, и я не мог понять, какое регулярное выражение использовать для поиска строк и возврата того же результата. Приведенный выше код дает мне то, что я хочу, это следующий массив:

#=>["magento2-base", "magento/module-sample-data", "magento/theme-adminhtml-backend", "magento2-base"]

Далее, хотя я все еще могу получить доступ к именам файлов и ключам из файла ha sh, мне нужно l oop через этот массив и создавать хэши, которые имеют значения массива в качестве ключа и имена файлов в качестве значений (добавляются к пути к файлу). Вот так (или я так думал):

    modules.each do |val|
        data_hash[:patches][val][key] = "m2-hotfixes/#{file}"
    end
end

Это та часть кода, с которой у меня возникают проблемы. Запуск этого дает мне следующую ошибку:

Traceback (most recent call last):
    4: from scrape.rb:10:in `<main>'
    3: from scrape.rb:10:in `each'
    2: from scrape.rb:18:in `block in <main>'
    1: from scrape.rb:18:in `each'
scrape.rb:19:in `block (2 levels) in <main>': undefined method `[]=' for nil:NilClass (NoMethodError)

Я заметил, что если я опущу key, например, так: data_hash до data_hash[:patches][val], я получу ха sh значений.

Итак, мой очевидный вопрос:

Почему мой подход к вложению хешей на один уровень дальше с использованием ключей не работает выше?

1 Ответ

0 голосов
/ 21 марта 2020

Вот ответ, который я придумал:

require 'json'

files_hash = Hash.new
file_hash = Hash.new
result_hash = Hash.new
data_hash = Hash.new
remap_hash = Hash.new 
final_hash = {"patches" => {}}
files = Dir["*.patch"]
patches_file = File.dirname(File.expand_path(__FILE__)) + "/patches.json"

files.each do |file|
    files_hash.store(files.index(file), file)
end
files_hash.each do |key, file|
    value = File.open(file, &:readline).split('/')[3]
    if value.match(/module-/) || value.match(/theme-/)
        result = "magento/#{value}"
    else
        result = "magento2-base"
    end
    data_hash[key] = result
    file_hash[key] = "m2-hotfixes/#{file}"
end

data_hash.each do |data_key, data_vals|
    file_hash.each do |file_key, file_vals|
        if data_key == file_key
            remap_hash[data_vals] = {
                "Patch #{data_key}" => file_vals
            }
        end
    end
end

final_hash["patches"].merge!(remap_hash)

File.open(patches_file, "w+") do |file|
    file.puts(final_hash.to_json)
end

Это дает следующее: patches.json NB: Я использовал набор файлов патчей, отличный от указанного выше, ключ здесь форматирование:

{
    "patches": {
        "magento2-base": {
            "Patch 6": "m2-hotfixes/pmet-fix-module-loader-algorithm.patch"
        },
        "magento/module-downloadable-sample-data": {
            "Patch 2": "m2-hotfixes/pmet-fix-sample-data-code-generator.patch"
        },
        "magento/module-customer": {
            "Patch 3": "m2-hotfixes/pmet-visitor-segment.patch"
        }
    }
}

Некоторые плюсы и минусы:

Плюсы

Работает. Удивительно.

Минусы

  1. Я знаю, что это может быть более элегантно

  2. Одна непредвиденная потребность, с которой я столкнулся, - это факт что мой patches.json файл может содержать дубликаты исправлений, которые необходимо применить к тому же файлу. Что-то вроде:

{
    "patches": {
        "magento2-base": {
            "Patch 1": "m2-hotfixes/pmet-add-install-module-timings.patch"
            "Patch 6": "m2-hotfixes/pmet-fix-module-loader-algorithm.patch"
        },
        "magento/module-downloadable-sample-data": {
            "Patch 2": "m2-hotfixes/pmet-fix-sample-data-code-generator.patch"
        },
        "magento/module-customer": {
            "Patch 3": "m2-hotfixes/pmet-visitor-segment.patch"
        }
    }
}

Мое решение должно учитывать это, поскольку Ruby не допускает дублирования ключей в хешах.

Я бы приветствовал более изящное решение проблемы, которая учитывала эту причуду.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...