[英]Using array values as hash keys to create nested hashes in Ruby
I have a directory of files.我有一个文件目录。 The majority of them are
.patch
files, although some of them are not.其中大部分是
.patch
文件,尽管其中一些不是。 For each patch file, I need to scan the first line which is always a string and extract a portion of that line.对于每个补丁文件,我需要扫描始终是字符串的第一行并提取该行的一部分。 With a combination of each file's name, that portion of each first line, and a unique identifier for each file, I need to create a hash which I will then convert to json and write to a file.
结合每个文件的名称、每个第一行的那部分以及每个文件的唯一标识符,我需要创建一个哈希,然后将其转换为 json 并写入文件。
Here are examples:以下是示例:
|__ .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
...
File Name: pmet-add-install-module-timings.patch
文件名:
pmet-add-install-module-timings.patch
First Line: diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php
第一行:
diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php
File Name: pmet-change-sample-data-load-order.patch
文件名:
pmet-change-sample-data-load-order.patch
First Line: diff --git a/vendor/magento/module-sample-data/etc/module.xml b/vendor/magento/module-sample-data/etc/module.xml
第一行:
diff --git a/vendor/magento/module-sample-data/etc/module.xml b/vendor/magento/module-sample-data/etc/module.xml
File Name: pmet-stop-catching-sample-data-errrors-during-install.patch
文件名:
pmet-stop-catching-sample-data-errrors-during-install.patch
First Line: diff --git a/vendor/magento/framework/Setup/SampleData/Executor.php b/vendor/magento/framework/Setup/SampleData/Executor.php
第一行:
diff --git a/vendor/magento/framework/Setup/SampleData/Executor.php b/vendor/magento/framework/Setup/SampleData/Executor.php
File Name: pmet-fix-admin-label-word-breaking.patch
文件名:
pmet-fix-admin-label-word-breaking.patch
First Line: diff --git a/vendor/magento/theme-adminhtml-backend/web/css/styles-old.less b/vendor/magento/theme-adminhtml-backend/web/css/styles-old.less
第一行:
diff --git a/vendor/magento/theme-adminhtml-backend/web/css/styles-old.less b/vendor/magento/theme-adminhtml-backend/web/css/styles-old.less
{
"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
scrape.rb
Here's the code in its entirety.这是完整的代码。 I will break it down further below:
我将在下面进一步分解:
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
Before I highlight the problem, I need to first detail what I've done to achieve the desired end result:在我强调这个问题之前,我需要首先详细说明我为达到预期的最终结果所做的工作:
First, I set up an empty files hash, module array, and data hash:首先,我设置了一个空文件哈希、模块数组和数据哈希:
files_hash = Hash.new
modules = Array.new
data_hash = {
patches: {}
}
Next, I scan the patch file directory for .patch
files and store them in the files hash with their keys.接下来,我扫描补丁文件目录中的
.patch
文件,并将它们与它们的密钥一起存储在文件散列中。 (I figure I can use the keys as the patch labels in the JSON file): (我想我可以使用密钥作为 JSON 文件中的补丁标签):
files = Dir["*.patch"]
files.each do |file|
files_hash.store(files.index(file), file)
end
Next, I use the file hash to read the first line of each patch file.接下来,我使用文件哈希读取每个补丁文件的第一行。 I notice a pattern in the patch files which I believe will be reliable: each file has either
magento/module-name
, magento/theme-name
or something else.我注意到补丁文件中有一个我认为可靠的模式:每个文件都有
magento/module-name
、 magento/theme-name
或其他东西。 Both the module-name
and theme-name
cases will use the magento/#{value}
syntax. module-name
和theme-name
案例都将使用magento/#{value}
语法。 The "something else" case will use magento/magento2-base
: “其他”案例将使用
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
...
This isn't the most ideal solution (what if the diff structure changes?) but it works for now, and I couldn't quite figure out the proper regex to use to search the strings and return the same result.这不是最理想的解决方案(如果 diff 结构发生变化怎么办?)但它现在有效,我无法弄清楚用于搜索字符串并返回相同结果的正确正则表达式。 The above code gives me what I want, which is the following array:
上面的代码给了我我想要的,这是以下数组:
#=>["magento2-base", "magento/module-sample-data", "magento/theme-adminhtml-backend", "magento2-base"]
Next, while still able to access the file names and keys from the file hash, I need to loop through this array and create hashes which have the array values as a key and the file names as values (appended to a file path).接下来,虽然仍然能够从文件哈希中访问文件名和键,但我需要遍历这个数组并创建以数组值作为键和文件名作为值(附加到文件路径)的哈希。 Like so, (or so I thought):
像这样,(或者我是这么认为的):
modules.each do |val|
data_hash[:patches][val][key] = "m2-hotfixes/#{file}"
end
end
It's this part of the code which I'm having issues with.这是我遇到问题的代码的这一部分。 Running this gives me the following error:
运行这会给我以下错误:
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)
I notice that if I omit key
like so: data_hash
to data_hash[:patches][val]
, I get a hash of values.我注意到,如果我像这样省略
key
: data_hash
到data_hash[:patches][val]
,我会得到一个值的散列。
So then, my obvious question:那么,我显而易见的问题是:
Why doesn't my approach of nesting the hashes one level further using keys work above?为什么我使用上面的键将哈希进一步嵌套一层的方法不起作用?
Here's the answer I've come up with:这是我想出的答案:
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
This yields the following: patches.json
NB: I used a different patches file set than above, the key is the formatting here:这会产生以下结果:
patches.json
注意:我使用了与上面不同的补丁文件集,关键是这里的格式:
{
"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"
}
}
}
Some pros and cons:一些优点和缺点:
It works.有用。 Awesome.
惊人的。
I know it can be more elegant我知道它可以更优雅
One unforeseen need I have run into is the fact that my patches.json
file may have duplicate patches which need to be applied to the same file.我遇到的一个不可预见的需求是我的
patches.json
文件可能有重复的补丁,需要应用到同一个文件。 Something like:就像是:
{
"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"
}
}
}
My solution needs to account for this, since Ruby doesn't allow for duplicate keys in hashes.我的解决方案需要考虑到这一点,因为 Ruby 不允许散列中有重复的键。
I would welcome a more elegant solution to the challenge that considered this quirk.对于考虑到这种怪癖的挑战,我欢迎一个更优雅的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.