sitef.rb 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # Sitef is a simple text format for serializing data to
  2. # It's intent is to be human readable and easy to
  3. # use for multi line text.
  4. module Sitef
  5. # All Sitef data is stored in files with one or more records.
  6. # Records are separated by separated by at least 2 dashes on a line.
  7. # Records contain key/value fields. The key starts in the first column
  8. # with a : and is followed by a : the value starts after the second :
  9. # A multiline key / value needs a key that starts with . and ends with .
  10. # the end of the value is a pair of dots .. by itself
  11. # Keys may not be nested, however, une could use spaces or dots,
  12. # or array indexes to emulate nexted keys.
  13. # A # at the start optionally after whitespace is a comment
  14. #
  15. def self.parse_file(file)
  16. lineno = 0
  17. results = []
  18. errors = []
  19. record = {}
  20. key = nil
  21. value = nil
  22. until file.eof?
  23. lineno += 1
  24. line = file.gets(256)
  25. # XXX does eof? even work???
  26. break if line.nil?
  27. next if line.empty?
  28. # new record
  29. if line[0,2] == '--'
  30. # Store last key used if any.
  31. if key
  32. record[key.downcase] = value.chomp
  33. key = nil
  34. end
  35. results << record
  36. record = {}
  37. elsif line[0] == '#'
  38. # Comments start with #
  39. elsif line[0] == ':'
  40. # a key/value pair
  41. key, value = line[1,line.size].split(':', 2)
  42. record[key.downcase] = value.chomp
  43. key = value = nil
  44. elsif line[0, 2] == '..'
  45. # end of multiline value
  46. record[key.downcase] = value.chomp
  47. key = value = nil
  48. elsif (line[0] == '.') && key.nil?
  49. # Multiline key/value starts here (but is ignored
  50. # until .. is encountered)
  51. key = line[1, line.size]
  52. value = ""
  53. elsif key
  54. # continue the value
  55. value << line
  56. else
  57. # Not in a key, sntax error.
  58. errors << "#{lineno}: Don't know how to process line"
  59. end
  60. end
  61. # Store last key used if any.
  62. if key
  63. record[key.downcase] = value.chomp
  64. end
  65. # store last record
  66. results << record unless record.empty?
  67. return results, errors
  68. end
  69. def self.load_filename(filename)
  70. results , errors, warnings = nil, nil, nil;
  71. file = File.open(filename, 'rt')
  72. return nil, ["Could not open #{filename}"] unless file
  73. begin
  74. results, errors = parse_file(file)
  75. ensure
  76. file.close
  77. end
  78. return results, errors
  79. end
  80. def self.save_field(file, key, value)
  81. sval = value.to_s
  82. if sval["\n"]
  83. file.puts(".#{key}\n")
  84. file.puts(sval)
  85. file.puts("\n..\n")
  86. else
  87. file.puts(":#{key}:#{sval}\n")
  88. end
  89. end
  90. def self.save_record(file, record)
  91. record.each do | key, value |
  92. save_field(file, key, value)
  93. end
  94. end
  95. def self.save_file(file, records)
  96. records.each do | record |
  97. save_record(file, record)
  98. file.puts("--\n")
  99. end
  100. end
  101. def self.save_filename(filename, records)
  102. results , errors = nil, nil
  103. file = File.open(filename, 'wt')
  104. return nil, ["Could not open #{filename}"] unless file
  105. begin
  106. results, errors = save_file(file, records)
  107. ensure
  108. file.close
  109. end
  110. return results, errors
  111. end
  112. end