一枪萄、需求
最近在做數(shù)據(jù)同步的應(yīng)用辛慰,需要弄一個配置文件app.yml來進(jìn)行應(yīng)用的設(shè)置超升,例如:
work_type: target
config:
name: bj-projects
tables:
- projects.employees
- info.cities
讀取出來很簡單:
yml_file = 'config/app.yml'
configs = ActiveSupport::HashWithIndifferentAccess.new(YAML.load(IO.read(yml_file)))
# => {"work_type"=>"target", "config"=>{"name"=>"bj-projects", "tables"=>["projects.employees", "info.cities"]}}
使用的時候是這樣的調(diào)用方式:
configs[:work_type], configs[:source][:config]
這種Hash的方式覺得很別扭,為什么不可以用這樣的方式呢九巡?
Config.work_type, Config.source
于是便發(fā)現(xiàn)了Struct和OpenStruct對象图贸。
二、Struct類
Struct在 Ruby 中是用純 C語言來實(shí)現(xiàn)的冕广, 用于快速聲明一個 Class, 例如:
dog = Struct.new("Dog", :name, :age)
fred = dog.new("fred", 5)
fred.age=6
printf "name:%s age:%d", fred.name, fred.age
等于你可以用Struct來迅速定義一個具有固定的屬性的對象疏日,在我的需求里面可以這樣來解決:
configs = Struct.new('Config', :work_type, :source)
Config = configs.new(....)
感覺還是有點(diǎn)繁瑣,不那么智能撒汉,而且對于沒有一開始指定的屬性沟优,就不能使用了,例如:
Config.name #會報錯
三睬辐、OpenStruct類
于是今天的主角OpenStruct需要亮相了挠阁。
An OpenStruct is a data structure, similar to a Hash, that allows the definition of arbitrary attributes with their accompanying values. This is accomplished by using Ruby’s metaprogramming to define methods on the class itself.
OpenStruct是一個類似于Hash的數(shù)據(jù)結(jié)構(gòu)宾肺,它可以允許定義任意的具有賦值的屬性。
require 'ostruct'
person = OpenStruct.new
person.name = "John Smith"
person.age = 70
person.pension = 300
puts person.name # -> "John Smith"
puts person.age # -> 70
puts person.address # -> nil
很神奇的地方鹃唯,就是你可以隨意指定它的屬性爱榕,一旦賦值這個屬性方法就存在了瓣喊。
另外一個很方便的定義方法坡慌,即通過Hash來進(jìn)行定義:
australia = OpenStruct.new(:country => "Australia", :population => 20_000_000)
p australia # -> <OpenStruct country="Australia" population=20000000>
直接把Hash中的鍵值轉(zhuǎn)換為類的屬性。這就是我們需要的方法了藻三。
yml_file = 'config/app.yml'
configs = ActiveSupport::HashWithIndifferentAccess.new(YAML.load(IO.read(yml_file)))
Config = OpenStruct.new(configs)
Config.work_type # => target
Config.source # => {name: ....}
# 然后還可以隨意自行添加方法
Config.name = Config.source['name']