如何读取包含数组的文件并在Ruby中使用它?

时间:2013-11-24 08:57:55

标签: ruby

我有以下工作正常。

app.rb

require "thor"

class App < Thor

  desc "list_recipes [KEYWORD] [OPTIONS]", "List all recipes. If a keyword is given, it filters the list based off it."
  option :format
  option :show_time, type: :boolean, default: true #--show-time --no-show-time
  def list_recipes keyword=nil
    recipes = [
      {
        title: "Ratatouille",
        cooking_time: "60 min",
        ingredients:  %w(potatoes carrots peppers onions zucchini tomatoes)
      },
      {
        title: "Mac & Cheese",
        cooking_time: "20 min",
        ingredients: %w(macarroni cheese mustard milk)
      },
      {
        title: "Caesar Salad",
        cooking_time: "10 min",
        ingredients:  %w(chicken lettuce croutons eggs)
      }
    ]

    recipes_to_be_listed = if keyword.nil? then recipes
                         else recipes.select { |recipe| recipe[:title].downcase.include? keyword.downcase}
                         end

    recipes_to_be_listed.each do | recipe |
      if options[:format].nil?
        print_default recipe
      else options[:format] == "oneline"
        print_oneline recipe
      end

    end
  end     

  private

  def print_default recipe
    puts "-------------"
    puts "Recipe: #{recipe[:title]}"
    puts "It takes: #{recipe[:cooking_time]} to cook."
    puts "The ingredients are: #{recipe[:ingredients].join(", ")}"
    puts ""
  end

  def print_oneline recipe
    if options[:show_time]
      time = "(#{recipe[:cooking_time]})"
    else
      time = ""
    end

    puts %Q{#{recipe[:title]} #{time}}
  end

end

App.start ARGV
# ARGV is for options, arguments, subcommand to be parsed in app.

现在我想通过阅读此文件来替换食谱。

recipes.txt

[
  {
    title: "Ratatouille",
    cooking_time: "60 min",
    ingredients:  %w(potatoes carrots peppers onions zucchini tomatoes)
  },
  {
    title: "Mac & Cheese",
    cooking_time: "20 min",
    ingredients: %w(macarroni cheese mustard milk)
  },
  {
    title: "Caesar Salad",
    cooking_time: "10 min",
    ingredients:  %w(chicken lettuce croutons eggs)
  }
]

然后我尝试了以下但是它出错了。

def list_recipes keyword=nil
  recipes = File.read('./recipes.txt')
..

读取包含数组并使用它的文件的最佳方法是什么?

3 个答案:

答案 0 :(得分:0)

您可以尝试将该文件作为字符串加载,然后使用eval对其进行评估。但想想安全性!

array = eval(File.read('recipes.txt'))

也许最好将Marshal形式化为文件或做一些Factory类来创建它。

或者您可以将此结构隐藏到另一个文件中的常量中,只需要该文件即可访问该常量。

答案 1 :(得分:0)

您已经在使用结构化的文本文件,因此您也可以一直使用。

recipe.txt可能如下所示:

@recipes = 
[
  {
    title: "Ratatouille",
    cooking_time: "60 min",
    ingredients:  %w(potatoes carrots peppers onions zucchini tomatoes)
  },
  {
    title: "Mac & Cheese",
    cooking_time: "20 min",
    ingredients: %w(macarroni cheese mustard milk)
  },
  {
    title: "Caesar Salad",
    cooking_time: "10 min",
    ingredients:  %w(chicken lettuce croutons eggs)
  }
]

您的代码可能如下所示:

load './recipe.txt'

您将能够访问该实例变量。

所以,如果你打算使用结构化文件,你也可以使用Ruby。直到你需要使用某种编组工具(例如YAML或其他任何东西)的某些“优势”,你真的不需要它。

以下是我用来确保代码的IRB会话:

>> load 'recipe.txt'                                                          
=> true                                                                       
>> @recipe                                                                    
=> nil                                                                        
>> @recipes                                                                   
=> [{:title=>"Ratatouille", :cooking_time=>"60 min", :ingredients=>["potatoes"
, "carrots", "peppers", "onions", "zucchini", "tomatoes"]}, {:title=>"Mac & Ch
eese", :cooking_time=>"20 min", :ingredients=>["macarroni", "cheese", "mustard
", "milk"]}, {:title=>"Caesar Salad", :cooking_time=>"10 min", :ingredients=>[
"chicken", "lettuce", "croutons", "eggs"]}]                                   

load可行,require的工作方式不同,因此无法使用此解决方案。

如此test.rb文件所示:

load './recipe.txt'
puts @recipes

# >> {:title=>"Ratatouille", :cooking_time=>"60 min", :ingredients=>["potatoes", "carrots", "peppers", "onions", "zucchini", "tomatoes"]}
# >> {:title=>"Mac & Cheese", :cooking_time=>"20 min", :ingredients=>["macarroni", "cheese", "mustard", "milk"]}
# >> {:title=>"Caesar Salad", :cooking_time=>"10 min", :ingredients=>["chicken", "lettuce", "croutons", "eggs"]}

答案 2 :(得分:0)

不要将数据保存为Ruby文件。重用它要困难得多,再加上它会在代码中打开潜在的漏洞,如果恶意用户获得了对文件系统的访问权,就可以利用这些漏洞。

相反,使用YAML或JSON之类的方法来序列化数据,同时使其可以被其他语言重用。

以下是数据:

data = [
  {
    title: "Ratatouille",
    cooking_time: "60 min",
    ingredients:  %w(potatoes carrots peppers onions zucchini tomatoes)
  },
  {
    title: "Mac & Cheese",
    cooking_time: "20 min",
    ingredients: %w(macarroni cheese mustard milk)
  },
  {
    title: "Caesar Salad",
    cooking_time: "10 min",
    ingredients:  %w(chicken lettuce croutons eggs)
  }
]

以下是YAML的外观:

require 'yaml'

puts data.to_yaml

# >> ---
# >> - :title: Ratatouille
# >>   :cooking_time: 60 min
# >>   :ingredients:
# >>   - potatoes
# >>   - carrots
# >>   - peppers
# >>   - onions
# >>   - zucchini
# >>   - tomatoes
# >> - :title: Mac & Cheese
# >>   :cooking_time: 20 min
# >>   :ingredients:
# >>   - macarroni
# >>   - cheese
# >>   - mustard
# >>   - milk
# >> - :title: Caesar Salad
# >>   :cooking_time: 10 min
# >>   :ingredients:
# >>   - chicken
# >>   - lettuce
# >>   - croutons
# >>   - eggs

请注意,它易于阅读,并可使用以下方式轻松检索:

data = YAML.load_file('path/to/the/data.yaml')

使用以下内容轻松编写:

File.write('path/to/the/data.yaml', data.to_yaml)

您也可以使用JSON,但YAML往往更容易阅读:

require 'json'
# >> [{"title":"Ratatouille","cooking_time":"60 min","ingredients":["potatoes","carrots","peppers","onions","zucchini","tomatoes"]},{"title":"Mac & Cheese","cooking_time":"20 min","ingredients":["macarroni","cheese","mustard","milk"]},{"title":"Caesar Salad","cooking_time":"10 min","ingredients":["chicken","lettuce","croutons","eggs"]}]

这是相同的JSON“美化”:

puts JSON.pretty_generate(data)
# >> [
# >>   {
# >>     "title": "Ratatouille",
# >>     "cooking_time": "60 min",
# >>     "ingredients": [
# >>       "potatoes",
# >>       "carrots",
# >>       "peppers",
# >>       "onions",
# >>       "zucchini",
# >>       "tomatoes"
# >>     ]
# >>   },
# >>   {
# >>     "title": "Mac & Cheese",
# >>     "cooking_time": "20 min",
# >>     "ingredients": [
# >>       "macarroni",
# >>       "cheese",
# >>       "mustard",
# >>       "milk"
# >>     ]
# >>   },
# >>   {
# >>     "title": "Caesar Salad",
# >>     "cooking_time": "10 min",
# >>     "ingredients": [
# >>       "chicken",
# >>       "lettuce",
# >>       "croutons",
# >>       "eggs"
# >>     ]
# >>   }
# >> ]

也可以使用以下内容轻松读取和解析JSON:

data = JSON[File.read('path/to/data.json')]

与YAML一样,JSON也很容易写入磁盘:

File.write('path/to/data.json', data.to_json)

在工作中,我们使用YAML来存储磁盘上的数据,使用JSON来获取我们在应用之间移动的数据;我们发现手动更容易阅读和修改YAML,并且JSON在整个线路上更有效。