我有以下课程:
require 'strscan'
class ConfParser
include Enumerable
class Error < StandardError; end
VERSION = '0.0.1'
SECTION_REGEX = /^\[ # Opening bracket
([^\]]+) # Section name
\]$ # Closing bracket
/x
PARAMETER_REGEX = /^\s*([^:]+) # Option
:
(.*?)$ # Value
/x
attr_accessor :filename, :sections
CONFIG_DIRECTORY = "./config"
ENCODING = "UTF-8"
def self.read(filename, opts = {})
new(opts.merge(:filename => filename))
end
def initialize(opts = {})
@filename = opts.fetch(:filename)
@separator = opts.fetch(:separator, ":")
@file = "#{CONFIG_DIRECTORY}/#{@filename}"
@content = nil
@config = Hash.new { |h,k| h[k] = Hash.new }
load
end
def load
raise_error("First line of config file contain be blank") if first_line_empty?
f = File.open(@file, 'r')
@content = f.read
parse!
ensure
f.close if f && !f.closed?
end
def sections
@config.keys
end
def [](section)
return nil if section.nil?
@config[section.to_s]
end
def []=( section, value )
@config[section.to_s] = value
end
private
def parse!
@_section = nil
@_current_line = nil
property = ''
string = ''
@config.clear
scanner = StringScanner.new(@content)
until scanner.eos?
@_current_line = scanner.check(%r/\A.*$/) if scanner.bol?
if scanner.scan(SECTION_REGEX)
@_section = @config[scanner[1]]
else
tmp = scanner.scan_until(%r/([\n"#{@param}#{@comment}] | \z | \\[\[\]#{@param}#{@comment}"])/mx)
raise_error if tmp.nil?
len = scanner[1].length
tmp.slice!(tmp.length - len, len)
scanner.pos = scanner.pos - len
string << tmp
end
end
process_property(property, string)
logger @config
end
def process_property( property, value )
value.chomp!
return if property.empty? and value.empty?
return if value.sub!(%r/\\\s*\z/, '')
property.strip!
value.strip!
parse_error if property.empty?
current_section[property.dup] = unescape_value(value.dup)
property.slice!(0, property.length)
value.slice!(0, value.length)
nil
end
def logger log
puts "*"*50
puts log
puts "*"*50
end
def first_line_empty?
File.readlines(@file).first.chomp.empty?
end
def raise_error(msg = 'Error processing line')
raise Error, "#{msg}: #{@_current_line}"
end
def current_section
@_section ||= @config['header']
end
end
上面的类解析了如下设置的文件:
[header]
project: Hello World
budget : 4.5
accessed :205
[meta data]
description : This is a tediously long description of the Hello World
project that you are taking. Tedious isn't the right word, but
it's the first word that comes to mind.
correction text: I meant 'moderately,' not 'tediously,' above.
[ trailer ]
budget:all out of budget.
你开始像这样运行:
require 'conf_parser'
cf = ConfParser.read "/path/to/conf/file"
出于某种原因,当parse!
方法运行时,会发生无限循环,我无法弄清楚原因。有什么理由会发生这种情况吗?我之前从未使用过StringScanner,所以可能是我缺乏对类的了解
答案 0 :(得分:1)
冒着明显的风险,你很可能永远不会满足scanner.eos?
,这反过来意味着你没有将扫描指针推进到字符串的末尾。由于scanner.pos
的{{1}}分支中else
的唯一更改是减少(即parse!
),这是可以理解的。如果len
分支没有将其推进到最后,您将永远不会终止。