我如何用heredoc插入文本文件的内容,用ruby插入变量

How i can Insert contents of text file with heredoc and variable with ruby

提问人:MMfood 提问时间:2/17/2023 更新时间:2/23/2023 访问量:261

问:

我创建 CLI 时出现问题。我想让用户有机会将他们的数据插入到文本文件中,为此我创建了一个文件并向其中添加了一个 heredoc 我正在尝试从文本文档中获取数据,该文本文档中有一个 heredoc,其中包含一个应该插值的函数 当我尝试显示文件的结果时,我得到了文件的全部内容,包括 heredoc

下面将是一个示例

我试图通过File类解决我的问题

variable_name = File::open("path_directory/file_with_heredoc.txt", "r+")::read

接下来,我决定通过以下方式将变量的值提供给终端

exec("echo #{variable_name}")

终端显示

file = <<-EOM
  single text with def result: #{upcase_def("Hello")}
EOM

试图通过结构给出,但结果没有变化

exec("echo #{variable_name.strip}")

我需要做什么才能只获取数据,而不获取 HEREDOC 语法? 我想得到这个结果

"single text with def result: HELLO"
红宝石 字符串 文件 heredoc

评论

0赞 spickermann 2/17/2023
你为什么要这样做?你到底想达到什么目的?您是否需要读取不同的文件?使用不同的变量名称?这些文件来自哪里?你能信任它们吗,或者这些文件是否可能包含恶意代码?
0赞 MMfood 2/17/2023
我正在使用 gli gem 做一个小宠物项目 用户决定创建的文件数量与用户决定创建的文件数量相同,但只能调用一个文件 我通过打开的文件创建文件 File::open(“./doc/#{fileName}.txt”, “w+”) do /f/ f.rwrite(“file = <<-EOM single text with def result: #{upcase_def(”Hello“)} EOM)
0赞 spickermann 2/17/2023
我不明白为什么您需要文件中的变量名称和 heredoc,特别是因为它具有文件扩展名而不是?为什么用户不能简单地将纯文本插入该文件,并在加载 txt 文件后将其分配给代码中的变量?这对用户来说会更容易,因为他们不必关心 Ruby 语法。而且它会更安全,因为您不需要评估来自不受信任的来源(用户)的代码。.txt.rb
0赞 MMfood 2/17/2023
好的,我会接受你的建议,从文档中删除heredoc。这是我的第一个项目,我只是熟悉了开发/系统设计的原理,所以我可能会犯错误

答:

0赞 Jan Vítek 2/17/2023 #1

我认为这就是您正在尝试做的事情,但我建议您首先做一些研究,为什么“eval()是邪恶的”。如果文件是用户(或黑客)输入的,您肯定希望在那里进行一些清理或采用完全不同的方法。

def upcase_def(str)
  str.upcase
end

data = File.read('file_with_heredoc.txt')
eval(data)
# => "  single text with def result: HELLO\n"

评论

0赞 spickermann 2/17/2023
这种方法的问题在于,OP在问题的第一段中描述用户将更改相关文件的内容。这意味着用户将能够将内容更改为任何内容,只要它是有效的 Ruby 代码,该代码就会被评估。这意味着如果用户愿意,他们将能够使用这种方法窃取机密或删除文件和数据......
1赞 Jan Vítek 2/17/2023
我发布这篇文章只是因为 OP 已经打电话并试图阻止他们使用我的解决方案。你已经对这个问题发表了评论,说“不要这样做”,我补充了我的“这可以做到,不要这样做”。如果 OP 问“如何使用占位符解析用户输入”之类的问题,答案将完全不同。exec()
0赞 Todd A. Jacobs 2/23/2023
@spickermann 您可以使用或 #inspect 使评估更安全。例如:将只返回一个 String 而不是实现赋值。虽然通常有比 Kernel#eval 更好的解决问题的方法,尤其是对于 OP 的用例,但我发现 Ruby 和 Bash 线程中“永远不要使用 eval!”的下意识克制很累。如果使用 eval 的有效用法为零,则该构造将从语言中删除。Q.E.D.公司%peval("%p" % "foo = 'bar'")
0赞 Todd A. Jacobs 2/23/2023 #2

Use File Methods to Read Text Files

A here-doc is really intended to inline long String objects directly into your code. Using it as storage for an external file or the contents of a CLI string argument is like using a saw to pound in a nail. Don't do that.

If you really want to store a here-doc in an external file, you should source that file (e.g. by using Kernel#load) rather than trying to parse it. In your case, this is still a bad idea because:

  1. You should never trust unsanitized user input.
  2. The sourced file could contain any Ruby code at all, which makes it at least as bad as Kernel#eval when called on untrusted data.
  3. If the external file is yours anyway, and you trust its contents, there are much easier ways to do this.

The easiest thing to do is simply read in the text file, either as a single String or as an Array of lines. You do this with File#read or File#readlines; these methods are inherited from the IO module, which is subclassed by File. For example:

# we'll assume the filename to read is the
# first argument to your script; otherwise
# just assign a filename as a String
text_file = ARGV[0]
 
# @return [String] all lines as a single
#   object stored in +str+
str = File.read text_file

# @return [Array<String>] array of lines
#   stored in +arr+
arr = File.readlines text_file

See Also