Деян обнови решението на 10.11.2014 08:49 (преди около 10 години)
+module RBFS
+ class File
+ attr_reader :data_type
+
+ def data
+ @data
+ end
+
+ def data=(data)
+ case data
+ when NilClass then @data_type = :nil
+ when TrueClass, FalseClass then @data_type = :boolean
+ when Symbol then @data_type = :symbol
+ when Numeric then @data_type = :number
+ when String then @data_type = :string
+ end
+ @data = data
+ end
+
+ def initialize(data = nil)
+ self.data = data
+ end
+
+
+ def serialize
+ "#{@data_type}:#{@data == nil ? 'nil' : @data}"
+ end
+
+ def to_s
+ serialize
+ end
+
+ def self.parse(string_data)
+ keyValuePair = string_data.split(':')
+ type = keyValuePair[0]
+ data = keyValuePair[1]
+ get_file(type, data)
+ end
+
+ def self.get_file(type, data)
+ return File.new(data.to_f) if /^\d+\.\d+$/ === data and type == 'number'
+ return File.new(data.to_i) if /^\d+$/ === data and type == 'number'
+ return File.new(data == 'true') if type === 'boolean'
+ return File.new(data.to_sym) if type == 'symbol'
+ return File.new(data) if type == 'string'
+ return File.new(nil) if type == 'nil'
+ end
+ end
+
+ class Directory
+ attr_accessor :is_root
+ attr_reader :files, :directories, :name
+
+ def initialize
+ @files = Hash.new
+ @directories = Hash.new
+ @is_root = true
+ end
+
+ def add_file(name, file)
+ @files[name] = file
+ @is_root = true
+ @name = name
+ end
+
+ def add_directory(name, directory = Directory.new)
+ @directories[name] = directory
+ directory.is_root = false
+ end
+
+ def [](name)
+ @directories[name] || @files[name]
+ end
+
+ def serialize
+ DirectorySerializer.serialize_directory('', self)
+ end
+
+
+ public
+ def self.parse(string_data, root = Directory.new)
+ DirectoryParser.parse(string_data, root)
+ return root
+ end
+ end
+
+ class DirectorySerializer
+ def self.serialize_directory(name, directory)
+ if DirectorySerializer.is_root_and_empty?(directory)
+ '0:0:'
+ elsif directory.directories.any?
+ DirectorySerializer.serialize_node_directory(name, directory)
+ else
+ DirectorySerializer.serialize_leaf_directory(name, directory)
+ end
+ end
+
+ def self.serialize_node_directory(name, directory)
+ files = DirectorySerializer.serialize_files(directory)
+ dirs = DirectorySerializer.serialize_dirs(directory)
+ if !directory.is_root
+ files_and_dirs = "#{files}#{dirs}"
+ "#{name}:#{files_and_dirs.length}:#{files}#{dirs}"
+ else
+ "#{files}#{dirs}"
+ end
+ end
+
+ def self.serialize_leaf_directory(name, directory)
+ serialized_files = serialize_files(directory)
+ "#{name}:#{serialized_files.length + 2}:#{serialized_files}0:"
+ end
+
+ def self.is_root_and_empty?(directory)
+ files = directory.files
+ directories = directory.directories
+ directory.is_root and !files.any? and !directories.any?
+ end
+
+ def self.serialize_dirs(directory)
+ dirs = "#{directory.directories.size}:"
+ directory.directories.each do |name, dir|
+ dir = serialize_directory(name, dir)
+ dirs << dir
+ end
+ dirs
+ end
+
+ def self.serialize_files(directory)
+ serialized_files = "#{directory.files.size}:"
+ directory.files.each do |name, file|
+ serialized_file = file.serialize
+ file_size = serialized_file.length
+ serialized_files << "#{name}:#{file_size}:#{serialized_file}"
+ end
+ serialized_files
+ end
+ end
+
+ class DirectoryParser
+ def self.parse(string_data, root = Directory.new)
+ @next_index = 0
+ DirectoryParser.parse_files(string_data, root)
+ DirectoryParser.parse_directories(string_data, root)
+ return root
+ end
+
+ def self.parse_files(string_data, root = Directory.new)
+ file_count = DirectoryParser.next_data(string_data).to_i
+ (1..file_count).each do |_|
+ file_name = DirectoryParser.next_data(string_data)
+ file_length = DirectoryParser.next_data(string_data).to_i
+ file_content = DirectoryParser.file_content(string_data, file_length)
+ root.add_file(file_name, File.parse(file_content))
+ end
+ end
+
+ def self.parse_directories(string_data, root = Directory.new)
+ dir_count = DirectoryParser.next_data(string_data).to_i
+
+ (1..dir_count).each do |_|
+ dir_name = DirectoryParser.next_data(string_data)
+ dir_length = DirectoryParser.next_data(string_data).to_i
+
+ root.add_directory(dir_name)
+ remaining_data = string_data[@next_index..string_data.length]
+ DirectoryParser.parse(remaining_data, root)
+ end
+ end
+
+ def self.next_data(string_data)
+ data = ''
+ indeces = (@next_index..string_data.length).to_a
+ $i = indeces[0]
+ while $i < string_data.length && string_data[$i] != ':' do
+ data << string_data[$i].to_s
+ $i += 1
+ end
+ @next_index = $i + 1
+ data
+ end
+
+ def self.file_content(string_data, file_length)
+ content = ''
+ indeces = (@next_index..string_data.length).to_a
+ index = indeces[0]
+ while content.length < file_length.to_i
+ content << string_data[index].to_s
+ index += 1
+ end
+ @next_index += file_length.to_i
+ content
+ end
+ end
+end