Венцислав обнови решението на 02.11.2014 22:09 (преди около 10 години)
+module RBFS
+
+ class File
+
+ attr_accessor :data
+
+ def initialize(data = nil)
+ if data.is_a?(Integer) or data.is_a?(Float) and data.to_f == data.to_i
+ @data = data.to_i
+ else
+ @data = data
+ end
+ end
+
+ def data_type
+ case @data
+ when nil then :nil
+ when String then :string
+ when Symbol then :symbol
+ when Integer, Float then :number
+ when TrueClass, FalseClass then :boolean
+ end
+ end
+
+ def serialize
+ "#{data_type.to_s}:#{@data.to_s}"
+ end
+
+ def self.parse(string_data)
+ splitted = string_data.split ':'
+ case splitted.first
+ when 'nil' then File.new
+ when 'string' then File.new splitted.last
+ when 'symbol' then File.new :"#{splitted.last}"
+ when 'number' then File.new splitted.last.to_f
+ when 'boolean'then File.new splitted.last == 'true'
+ end
+ end
+
+ end
+
+ class Directory
+
+ attr_reader :directories, :files
+
+ def initialize
+ @files = {}
+ @directories = {}
+ end
+
+ def add_file(name, file)
+ @files[name] = file
+ end
+
+ def add_directory(name, directory = nil)
+ @directories[name] = directory || Directory.new
+ end
+
+ def [](name)
+ if directories.has_key? name
+ directories[name]
+ elsif files.has_key? name
+ files[name]
+ else
+ nil
+ end
+ end
+
+ def serialize
+ result = "#{files.size}:"
+ files.each do |name, file|
+ result += "#{name}:#{file.serialize.size}:#{file.serialize}"
+ end
+ result += "#{directories.size}:"
+ directories.each do |name, directory|
+ result += "#{name}:#{directory.serialize.size}:#{directory.serialize}"
+ end
+ result
+ end
+
+ def self.parse(string_data)
+ directory = Directory.new
+
+ self.parse_files(string_data, directory)
+ self.parse_directories(string_data, directory)
+
+ directory
+ end
+
+ private
+
+ def self.parse_files(string_data, directory)
+ files_count = string_data.slice!(/\d+:/)[0..-2].to_i
+ files_count.times do
+ file_name = string_data.slice!(0..string_data.index(':'))[0..-2]
+ file_content_length = string_data.slice!(/\d+:/)[0..-2].to_i
+ directory.add_file(file_name, File.parse(string_data[0..file_content_length-1]))
+ string_data.slice!(0, file_content_length)
+ end
+ end
+
+ def self.parse_directories(string_data, directory)
+ directories_count = string_data.slice!(/\d+:/)[0..-2].to_i
+ directories_count.times do
+ directory_name = string_data.slice!(0..string_data.index(':'))[0..-2]
+ directory_content_length = string_data.slice!(/\d+:/)[0..-2].to_i
+ directory.add_directory(
+ directory_name,
+ Directory.parse(string_data[0..directory_content_length-1]))
+ string_data.slice!(0, directory_content_length)
+ end
+ end
+
+ end
+
+end
Здравей :)
Решението ти е хубаво, но имам няколко коментара:
- Аз не бих слагал празни редове след дефиницията на модул и клас (както и преди затварящия им
end
). - Преобразуването на типовете във
File#initialize
не е нужно - няма такова изискване в условието. - Не е нужно да извикваш
to_s
на нещата, които интерполираш. - Този ред не ми допада:
splitted = string_data.split ':'
. Защо не "разопаковаш" масива при присвояването? Освен това, помисли какво ще се случи, ако в съдържанието на файла има:
. - Можеш ли се сетиш как да изкараш
File.new
извънcase
-a? Много се повтаря. :) -
:"#{splitted.last}"
не е нормалният начин да преобразувашString
вSymbol
. Подсказвам -String
има специален метод за това. - Стойностите по подразбиране на аргументи може да са всякакви изрази - използвай това в
add_directory
. - За
[]
може да използваш нещо, което си използвал вadd_directory
. Без да проверяваш дали има такъв ключ. :) - В
serialize
може да използвашmap
, без да конкатенираш постоянно в низовe. Според мен ще стане по-чисто. Освен това, извиквашserialize
по два пъти за всеки файл и директория. Най-добре е да си го запазиш в променлива и да го използваш от там.
За парсването:
- Защо използваш
slice
иindex
вместоsplit
? Разгледай документацията наsplit
ако си мислиш, че той не ти върши работа. - Методите
parse_files
иparse_directories
са аналогични с точност до имена на променливи иFile
vsDirectory
. Опитай се да ги обединиш, като отделиш различните части. - Мутираш низа, който е подаден на
parse
. На лекции сме споменавали защо това е лоша практика. :)
Може да ти е полезно да си направиш отделен клас, който се занимава с парсването. Той може да има някакво подходящо вътрешно състояние, което да те улесни. :)