Вы неправильно поняли, что делают readlines
и read
, а также содержимое вашего файла. Начнем с таких вещей:
- Файлы не содержат массивов или хешей - они содержат текст, который, возможно, может быть проанализирован в массивы или хеши.
File.read
считывает содержимое файла в строку.
File.readlines
считывает содержимое файла в массив, содержащий строки, где каждая строка является одной строкой файла. Он (примерно) эквивалентен File.read('filename.txt').split("\n")
.
Итак, рассмотрим файл, который содержит (скорректированный на правильность синтаксиса Ruby)
[{name: "Muhammad"},{name: "Mahmoud"}]
Хотя это выглядит вам нравится массив, содержащий хеши, скобки не имеют смысловое значение.Давайте прочитаем его:
> data = File.read('file.txt')
=> "[{name: \"Muhammad\"},{name: \"Mahmoud\"}]\n"
Примечание несколько вещей:
- Есть цитаты, окружающие ваши данные - это строка
- Кавычки в файле (
"Muhammad"
) экранируются
- Там представляет собой
\n
в конце строки, означая новую строку
Мы можем спросить data
то, что она есть, и мы можем напечатать его, чтобы увидеть, что это действительно ваше содержимое файла без экранирования:
> data.class
=> String
> puts data
[{name: "Muhammad"},{name: "Mahmoud"}]
=> nil
Теперь давайте попробуем File.readlines
:
> lines = File.readlines('file.txt')
=> ["[{name: \"Muhammad\"},{name: \"Mahmoud\"}]\n"]
Примечание Кронштейнов окружающего ту же строку, которую мы имели до. Это массив, содержащий одну строку, которая была первой (единственной) строкой в вашем файле.
> lines.class
=> Array
> lines.size
=> 1
> puts lines.first
[{name: "Muhammad"},{name: "Mahmoud"}]
=> nil
> lines.first == data
=> true
Теперь мы можем перейти к ошибке, которую вы видите. Когда вы использовали readlines
, а затем добавили hash
, вы добавляли хэш в массив. Это совершенно законно в Ruby, потому что у вас могут быть массивы, содержащие элементы разных типов. Когда вы добавили hash
, вы получили массив, содержащий строку и хэш.
> hash = {name: "Ahmed"}
=> {:name=>"Ahmed"}
> lines << hash
=> ["[{name: \"Muhammad\"},{name: \"Mahmoud\"}]\n", {:name=>"Ahmed"}]
> lines.map(&:class)
=> [String, Hash]
> lines.size
=> 2
Но, когда вы пытались добавить хэш результата read
, вы добавить хэш строки, которая Руби не будет делать.
> data << hash
TypeError: no implicit conversion of Hash into String
Так, чтобы ответить на ваш вопрос в заголовке, вы можете добавить хэш в массив, вы просто не понимаете, что вы имели, и ваш массив первоначально не содержат данные, как вы ожидали его.
Чтобы прочитать ваш файл в виде массива Ruby, содержащего хеши, вы можете использовать eval
, который выполняет строку, содержащую код Ruby. Это обычно не рекомендуется, потому что, например, если вы запустили его на данные, предоставленные другим пользователем, он может содержать код, который вы действительно не хотите выполнять. Поскольку вы управляете этим файлом, и это ваши собственные данные, в этом случае это достаточно безопасно.
> real_data = eval(File.read('file.txt'))
=> [{:name=>"Muhammad"}, {:name=>"Mahmoud"}]
> real_data.class
=> Array
> real_data.first
=> {:name=>"Muhammad"}
> real_data << hash
=> [{:name=>"Muhammad"}, {:name=>"Mahmoud"}, {:name=>"Ahmed"}]
Теперь у вас есть массив, содержащий рубин рубин хэш, и вы можете добавить еще один окрошку пути, который вы ожидаете.
'[{: name" Muhammad "}, {: name" Mahmoud "}]' throws error (это не действительный Hash или Array), интересно, как работает этот код ... – karatedog
Файл содержит только символы , без массивов или других объектов Ruby. Предположим, что эти символы - '' [{: name "Muhammad"}, {: name "Mahmoud"}] ''. Вы можете прочитать это в строке: 'str = File.read (file.txt) # =>" [{: name \ "Muhammad \"}, {: name \ "Mahmoud \"}] "'. (Нет глобальной переменной здесь, пожалуйста!). Если 'hash # => {: a => 1}', скажем, 'str << hash' поднимет указанное вами исключение, потому что аргумент' << ''должен быть строкой. –
Serhat, вам нужно '[{: name =>« Muhammad »}, {: name =>« Mahmoud »}]' или '[{name:" Muhammad "}, {name:" Mahmoud "}]'. –