我的配置中有很多环境变量:
DB_HOSTNAME=something.rds.amazonaws.com
DB_PORTNUM=9999
DB_USERNAME=production
DB_PASSWORD=xyzzy
要从中创建数据库连接字符串,请执行以下操作:
"postgres://" +
"#{ENV['DB_USERNAME']}#{ENV['DB_PASSWORD'] ? ":#{ENV['DB_PASSWORD']}" : nil}" +
"@#{ENV['DB_HOSTNAME']}#{ENV['DB_PORTNUM'] ? ":#{ENV['DB_PORTNUM']}" : nil}" +
"/proper_scraper_#{$environment}"
这样,它可以在开发/测试中工作,DB_PASSWORD
和DB_PORTNUM
没有设置,并且可以在生产中工作。但这有点难看:
ENV['DB_PASSWORD'] ? ":#{ENV['DB_PASSWORD']}" : nil
所需的语义是:如果不是nil,则前置,否则返回nil。理想情况下会是这样的:
ENV['DB_PASSWORD'].try(:prepend, ':')
使用像这样的Object.try:
def try method, *args
send(method, *args) if respond_to? method
end
但这不起作用,因为prepend会改变字符串(为什么?)和env字符串被冻结。替代方案:
ENV['DB_PASSWORD'].dup.try(:prepend, ':')
但是,如果未设置环境变量,则此功能无效,因为您无法复制nil。
这里有一个漂亮的单行或我是否陷入混乱?
答案 0 :(得分:4)
使用对象和标准库:
require 'uri'
u = URI::Generic.build(
scheme: "postgres",
host: ENV["DB_HOSTNAME"],
port: ENV["DB_PORTNUM"],
path: "/proper_scraper_#{$environment}",
)
u.user = ENV["DB_USERNAME"]
u.password = ENV["DB_PASSWORD"]
puts u.to_s
答案 1 :(得分:3)
遗憾的是,String#insert
和String#prepend
都修改了字符串,但String#sub
应该有效:
ENV['DB_PASSWORD'].try(:sub,'',':')
或者有点意图:
ENV['DB_PASSWORD'].try(:sub,/^/,':')
答案 2 :(得分:1)
如果Object#try
恰好支持块(如ActiveSupport),
ENV['DB_PASSWORD'].try { |s| ":#{s}" }
答案 3 :(得分:1)
在红宝石2.3
中,您可以将safe navigation operator与String#sub
(作为@Matt
pointed out)结合使用
ENV["DB_PASSWORD]&.sub(/^/, ":")
答案 4 :(得分:0)
唉。你的可读性确实受到了影响,因为你试图在一行中完成所有工作。不要那样做。
我会做类似的事情:
为示例设置ENV ...
ENV['DB_HOSTNAME'] = 'something.rds.amazonaws.com'
ENV['DB_PORTNUM'] = '9999'
ENV['DB_USERNAME'] = 'production'
ENV['DB_PASSWORD'] = 'xyzzy'
真正的代码从这里开始:
$environment = 'production'
db_hostname, db_portnum, db_username, db_password = %w[
DB_HOSTNAME
DB_PORTNUM
DB_USERNAME
DB_PASSWORD
].map{ |e| ENV[e] }
db_password = ':' + db_password if db_password
db_portnum = ':' + db_portnum if db_portnum
DSN = "postgres://%s%s@%s%s%s" % [
db_username,
db_password,
db_hostname,
db_portnum,
"/proper_scraper_#{$environment}"
]
DSN # => "postgres://production:xyzzy@something.rds.amazonaws.com:9999/proper_scraper_production"
三元语句是if
/ then
/ else
语句的替代,而非简单if
/ then
。试图使它们合适只会导致代码混乱,所以不要去那里。
人们迷恋于一行中的填充代码,很久以前,当我们使用解释的BASIC时,它帮助加速了代码,但今天的语言很少从中受益。相反,它会使代码难以辨认。编写难以理解的代码是一种快速通道,可以在代码审查中调用自己来解释自己,然后被告知要重写它并且永远不会再这样做。