Class: Cute::ConfigParser

Inherits:
Object
  • Object
show all
Defined in:
lib/cute/configparser.rb

Overview

Sample file:

database:

user: myser
password: thepassword
ip: 127.0.0.1

cache:

size: 1234
# default directory: /tmp
# default strict: true

# default values for environments fields

Parser

cp = ConfigParser.new(yamlstr) conf = :db=>{, :cache=>{}, :env=>{}, :pxe => {}} cp.parse(‘database’,true) do

# String with default value
conf[:db][:user] = cp.value('user',String,nil,'defaultvalue')
# Mandatory String
conf[:db][:password] = cp.value('password',String)
# String with multiple possible values
conf[:db][:kind] = cp.value('kind',String,nil,['MySQL','PostGRE','Oracle'])
# Regexp
conf[:db][:ip] = cp.value('ip',String,'127.0.0.1',
  /\A\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\Z/
)

end cp.parse(‘cache’,true) do

# Integer with default value
conf[:cache][:size] = cp.value('size',Fixnum,nil,100)
# Directory that need to exist and be r/w
conf[:cache][:directory] = cp.value('directory',String,'/tmp',
  {
    :type => 'dir',
    :readable => true,
    :writable => true,
    :create => true,
    :mode => 0700
  }
)
# Boolean
conf[:cache][:strict] = cp.value('strict',[TrueClass,FalseClass],true)

end

# Non-mandatory field cp.parse(‘environments’) do

# Specification of a unix path
conf[:env][:tar_dir] = cp.value('tarball_dir',String,'/tmp',Pathname)
# Add a prefix to a value
conf[:env][:user_dir] = cp.value('user_dir',String,'/tmp',
  {:type => 'dir', :prefix => '/home/'}
)

end

Constant Summary collapse

PATH_SEPARATOR =
'/'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(confighash) ⇒ ConfigParser

Returns a new instance of ConfigParser.



69
70
71
72
73
74
75
# File 'lib/cute/configparser.rb', line 69

def initialize(confighash)
  @basehash = confighash
  # The current path
  @path = []
  # The current value
  @val = confighash
end

Instance Attribute Details

#basehashObject (readonly)

Returns the value of attribute basehash.



66
67
68
# File 'lib/cute/configparser.rb', line 66

def basehash
  @basehash
end

Class Method Details

.errmsg(field, message) ⇒ Object



115
116
117
# File 'lib/cute/configparser.rb', line 115

def self.errmsg(field,message)
  "#{message} [field: #{field}]"
end

.pathstr(array) ⇒ Object



119
120
121
# File 'lib/cute/configparser.rb', line 119

def self.pathstr(array)
  array.compact.join(PATH_SEPARATOR)
end

Instance Method Details

#check_array(val, array, _fieldname) ⇒ Object



169
170
171
172
173
174
175
176
177
178
# File 'lib/cute/configparser.rb', line 169

def check_array(val, array, _fieldname)
  unless array.include?(val)
    raise ParserError.new(
      "Invalid value '#{val}', allowed value"\
      "#{(array.size == 1 ? " is" : "s are")}: "\
      "#{(array.size == 1 ? '' : "'#{array[0..-2].join("', '")}' or ")}"\
      "'#{array[-1]}'"
    )
  end
end

#check_dir(val, _dir, _fieldname) ⇒ Object

A directory, checking if exists (creating it otherwise) and writable



209
210
211
212
213
214
215
216
217
# File 'lib/cute/configparser.rb', line 209

def check_dir(val, _dir, _fieldname)
  if File.exist?(val)
    unless File.directory?(val)
      raise ParserError.new("'#{val}' is not a regular directory")
    end
  else
    raise ParserError.new("The directory '#{val}' does not exists")
  end
end

#check_field(fieldname, mandatory, type) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/cute/configparser.rb', line 123

def check_field(fieldname,mandatory,type)
  begin
    if @val.is_a?(Hash)
      if !@val[fieldname].nil?
        if type.is_a?(Class)
          typeok = @val[fieldname].is_a?(type)
        elsif type.is_a?(Array)
          type.each do |t|
            typeok = @val[fieldname].is_a?(t)
            break if typeok
          end
        else
          raise 'Internal Error'
        end

        if typeok
          yield(@val[fieldname])
        else
          $,=','
          typename = type.to_s
          $,=nil
          raise ParserError.new(
            "The field should have the type #{typename}"
          )
        end
      elsif mandatory
        raise ParserError.new("The field is mandatory")
      else
        yield(nil)
      end
    elsif mandatory
      if @val.nil?
        raise ParserError.new("The field is mandatory")
      else
        raise ParserError.new("The field has to be a Hash")
      end
    else
      yield(nil)
    end
  rescue ParserError => pe
    raise ArgumentError.new(
      ConfigParser.errmsg(path(fieldname),pe.message)
    )
  end
end

#check_file(val, _file, _fieldname) ⇒ Object

A file, checking if exists (creating it otherwise) and writable



198
199
200
201
202
203
204
205
206
# File 'lib/cute/configparser.rb', line 198

def check_file(val, _file, _fieldname)
  if File.exist?(val)
    unless File.file?(val)
      raise ParserError.new("The file '#{val}' is not a regular file")
    end
  else
    raise ParserError.new("The file '#{val}' does not exists")
  end
end

#check_hash(val, hash, fieldname) ⇒ Object



180
181
182
# File 'lib/cute/configparser.rb', line 180

def check_hash(val, hash, fieldname)
  self.send("customcheck_#{hash[:type].downcase}".to_sym,val,fieldname,hash)
end

#check_pathname(val, _pathname, _fieldname) ⇒ Object

A pathname, checking if exists (creating it otherwise) and writable



220
221
222
223
224
225
226
# File 'lib/cute/configparser.rb', line 220

def check_pathname(val, _pathname, _fieldname)
  begin
    Pathname.new(val)
  rescue
    raise ParserError.new("Invalid pathname '#{val}'")
  end
end

#check_range(val, range, fieldname) ⇒ Object



184
185
186
# File 'lib/cute/configparser.rb', line 184

def check_range(val, range, fieldname)
  check_array(val, range.entries, fieldname)
end

#check_regexp(val, regexp, _fieldname) ⇒ Object



188
189
190
191
192
193
194
195
# File 'lib/cute/configparser.rb', line 188

def check_regexp(val, regexp, _fieldname)
  unless val =~ regexp
    raise ParserError.new(
      "Invalid value '#{val}', the value must have the form (ruby-regexp): "\
      "#{regexp.source}"
    )
  end
end

#check_string(val, str, _fieldname) ⇒ Object



228
229
230
231
232
233
234
# File 'lib/cute/configparser.rb', line 228

def check_string(val, str, _fieldname)
  unless val == str
    raise ParserError.new(
      "Invalid value '#{val}', allowed values are: '#{str}'"
    )
  end
end

#curvalObject



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/cute/configparser.rb', line 95

def curval
  ret = @basehash
  @path.compact.each do |field|
    begin
      field = Integer(field)
    rescue ArgumentError => e
      puts "Error: #{e.message}"
      puts "#{e.backtrace}"
    end

    if ret[field]
      ret = ret[field]
    else
      ret = nil
      break
    end
  end
  ret
end

#customcheck_code(_val, _fieldname, args) ⇒ Object



236
237
238
239
240
241
242
# File 'lib/cute/configparser.rb', line 236

def customcheck_code(_val, _fieldname, args)
  begin
    eval("#{args[:prefix]}#{args[:code]}#{args[:suffix]}")
  rescue
    raise ParserError.new("Invalid expression '#{args[:code]}'")
  end
end

#customcheck_dir(val, _fieldname, args) ⇒ Object



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/cute/configparser.rb', line 279

def customcheck_dir(val, _fieldname, args)
  return if args[:disable]
  val = File.join(args[:prefix],val) if args[:prefix]
  val = File.join(val,args[:suffix]) if args[:suffix]
  if File.exist?(val)
    if File.directory?(val)
      if args[:writable]
        unless File.stat(val).writable?
          raise ParserError.new("The directory '#{val}' is not writable")
        end
      end

      if args[:readable]
        unless File.stat(val).readable?
          raise ParserError.new("The directory '#{val}' is not readable")
        end
      end
    else
      raise ParserError.new("'#{val}' is not a regular directory")
    end
  else
    if args[:create]
      begin
        puts "The directory '#{val}' does not exists, let's create it"
        tmp = FileUtils.mkdir_p(val, :mode => (args[:mode] || 0700))
        raise if tmp.is_a?(FalseClass)
      rescue
        raise ParserError.new("Cannot create the directory '#{val}'")
      end
    else
      raise ParserError.new("The directory '#{val}' does not exists")
    end
  end
end

#customcheck_file(val, _fieldname, args) ⇒ Object



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/cute/configparser.rb', line 244

def customcheck_file(val, _fieldname, args)
  return if args[:disable]
  val = File.join(args[:prefix],val) if args[:prefix]
  val = File.join(val,args[:suffix]) if args[:suffix]
  if File.exist?(val)
    if File.file?(val)
      if args[:writable]
        unless File.stat(val).writable?
          raise ParserError.new("The file '#{val}' is not writable")
        end
      end

      if args[:readable]
        unless File.stat(val).readable?
          raise ParserError.new("The file '#{val}' is not readable")
        end
      end
    else
      raise ParserError.new("The file '#{val}' is not a regular file")
    end
  else
    if args[:create]
      begin
        puts "The file '#{val}' does not exists, let's create it"
        tmp = FileUtils.touch(val)
        raise if tmp.is_a?(FalseClass)
      rescue
        raise ParserError.new("Cannot create the file '#{val}'")
      end
    else
      raise ParserError.new("The file '#{val}' does not exists")
    end
  end
end

#depthObject



87
88
89
# File 'lib/cute/configparser.rb', line 87

def depth
  @path.size
end

#parse(fieldname, mandatory = false, type = Hash) ⇒ Object



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/cute/configparser.rb', line 315

def parse(fieldname, mandatory=false, type=Hash)
  check_field(fieldname,mandatory,type) do |curval|
    oldval = @val
    push(fieldname, curval)

    if curval.is_a?(Array)
      curval.each_index do |i|
        push(i)
        yield({
          :val => curval,
          :empty => curval.nil?,
          :path => path,
          :iter => i,
        })
        pop()
      end
      curval.clear
    else
      yield({
        :val => curval,
        :empty => curval.nil?,
        :path => path,
        :iter => 0,
      })
    end

    oldval.delete(fieldname) if curval and curval.empty?

    pop(oldval)
  end
end

#path(val = nil) ⇒ Object



91
92
93
# File 'lib/cute/configparser.rb', line 91

def path(val=nil)
  ConfigParser.pathstr(@path + [val])
end

#pop(val = nil) ⇒ Object



82
83
84
85
# File 'lib/cute/configparser.rb', line 82

def pop(val=nil)
  @path.pop
  @val = (val.nil? ? curval() : val)
end

#push(fieldname, val = nil) ⇒ Object



77
78
79
80
# File 'lib/cute/configparser.rb', line 77

def push(fieldname, val=nil)
  @path.push(fieldname)
  @val = (val.nil? ? curval() : val)
end

#unused(result = [], curval = nil, curpath = nil) ⇒ Object



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/cute/configparser.rb', line 374

def unused(result = [],curval=nil,curpath=nil)
  curval = @basehash if curval.nil?
  curpath = [] unless curpath

  if curval.is_a?(Hash)
    curval.each do |key,value|
      curpath << key
      if value.nil?
        result << ConfigParser.pathstr(curpath)
      else
        unused(result,value,curpath)
      end
      curpath.pop
    end
  elsif curval.is_a?(Array)
    curval.each_index do |i|
      curpath << i
      if curval[i].nil?
        result << ConfigParser.pathstr(curpath)
      else
        unused(result,curval[i],curpath)
      end
      curpath.pop
    end
  else
    result << ConfigParser.pathstr(curpath)
  end

  result
end

#value(fieldname, type, defaultvalue = nil, expected = nil) ⇒ Object

if no defaultvalue defined, field is mandatory



348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/cute/configparser.rb', line 348

def value(fieldname,type,defaultvalue=nil,expected=nil)
  ret = nil
  check_field(fieldname,defaultvalue.nil?,type) do |val|
    if val.nil?
      ret = defaultvalue
    else
      ret = val
      @val.delete(fieldname)
    end
    #ret = (val.nil? ? defaultvalue : val)

    if expected
      classname = (
        expected.class == Class ? expected.name : expected.class.name
      ).split('::').last
      self.send(
        "check_#{classname.downcase}".to_sym,
        ret,
        expected,
        fieldname
      )
    end
  end
  ret
end