Решение на Трета задача от Венцислав Димитров

Обратно към всички решения

Към профила на Венцислав Димитров

Резултати

  • 6 точки от тестове
  • 0 бонус точки
  • 6 точки общо
  • 44 успешни тест(а)
  • 0 неуспешни тест(а)

Код

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}:#{@data}"
end
def self.parse(string_data)
splitted = string_data.split ':', 2
File.new case splitted.first
when 'nil' then
when 'string' then splitted.last
when 'symbol' then splitted.last.to_sym
when 'number' then splitted.last.to_f
when 'boolean'then 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 = Directory.new)
@directories[name] = directory
end
def [](name)
directories[name] || files[name] || nil
end
def serialize
"#{files.size}:" + files.map do |name, file|
file_serialized = file.serialize
"#{name}:#{file_serialized.size}:#{file_serialized}"
end.join('') +
"#{directories.size}:" + directories.map do |name, directory|
directory_serialized = directory.serialize
"#{name}:#{directory_serialized.size}:#{directory_serialized}"
end.join('')
end
def self.parse(string_data)
directory = Directory.new
string_data_copy = string_data.dup
self.parse_files(string_data_copy, directory)
self.parse_directories(string_data_copy, 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

Лог от изпълнението

............................................

Finished in 0.0442 seconds
44 examples, 0 failures

История (2 версии и 1 коментар)

Венцислав обнови решението на 02.11.2014 22:09 (преди над 9 години)

+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 vs Directory. Опитай се да ги обединиш, като отделиш различните части.
  • Мутираш низа, който е подаден на parse. На лекции сме споменавали защо това е лоша практика. :)

Може да ти е полезно да си направиш отделен клас, който се занимава с парсването. Той може да има някакво подходящо вътрешно състояние, което да те улесни. :)

Венцислав обнови решението на 09.11.2014 13:31 (преди над 9 години)

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}"
+ "#{data_type}:#{@data}"
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'
+ splitted = string_data.split ':', 2
+ File.new case splitted.first
+ when 'nil' then
+ when 'string' then splitted.last
+ when 'symbol' then splitted.last.to_sym
+ when 'number' then splitted.last.to_f
+ when 'boolean'then 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
+ def add_directory(name, directory = Directory.new)
+ @directories[name] = directory
end
def [](name)
- if directories.has_key? name
- directories[name]
- elsif files.has_key? name
- files[name]
- else
- nil
- end
+ directories[name] || files[name] || nil
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
+ "#{files.size}:" + files.map do |name, file|
+ file_serialized = file.serialize
+ "#{name}:#{file_serialized.size}:#{file_serialized}"
+ end.join('') +
+ "#{directories.size}:" + directories.map do |name, directory|
+ directory_serialized = directory.serialize
+ "#{name}:#{directory_serialized.size}:#{directory_serialized}"
+ end.join('')
end
def self.parse(string_data)
directory = Directory.new
+ string_data_copy = string_data.dup
+ self.parse_files(string_data_copy, directory)
+ self.parse_directories(string_data_copy, directory)
- 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