Решение на Трета задача от Яни Малцев

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

Към профила на Яни Малцев

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 33 успешни тест(а)
  • 11 неуспешни тест(а)

Код

module RBFS
class File
attr_accessor :data
attr_accessor :data_type
def initialize (start_data = nil)
@data = start_data
set_data_type(start_data)
end
def data=(new_data)
@data = new_data
set_data_type(new_data)
end
def data_type=(new_type)
@data_type = new_type
case @new_type
when :nil then @data = nil
when :string then @data = @data.to_s
when :number then @data = @data.to_f
when :symbol then @data = @data.to_sym
when :boolean then @data = @data == "true"
end
end
def serialize
@data_type.to_s + ":" + @data.to_s
end
def File.parse(parse_string)
ret = File.new
ret.data = parse_string.split(":")[1]
ret.data_type = parse_string.split(":")[0].to_sym
ret
end
private
def set_data_type(start_data)
case start_data
when NilClass then @data_type = :nil
when String then @data_type = :string
when Integer || Float then @data_type = :number
when Symbol then @data_type = :symbol
when TrueClass || FalseClass then @data_type = :boolean
end
end
end
class Directory
attr :files, true
attr :directories, true
def initialize
@files = Hash.new
@directories = Hash.new
end
def add_file(file_name, file_data)
@files[file_name] = file_data
end
def add_directory(directory_name, directory_data = RBFS::Directory.new)
@directories[directory_name] = directory_data
end
def serialize
ret = @files.size.to_s.concat(":")
@files.each_pair{ |a, b|
ret << a << ":" << b.serialize.length.to_s << ":" << b.serialize }
ret << @directories.size.to_s << ":"
@directories.each_pair{ | a, b | #Skeptic:Space=symbol, Style Guide align conflict
ret << a << ":" << b.serialize.length.to_s << ":" << b.serialize }
ret
end
def [](index_name)
ret = @files[index_name] || @directories[index_name]
end
def Directory.parse( parse_string)
return_dir = RBFS::Directory.new
parser = Parser.new(parse_string)
parser.first_parts.each_pair{ | name , data |
return_dir.add_file(name, File.parse(data)) }
parser.second_parts.each_pair{ | name , data | #Same problem with Skeptic
return_dir.add_directory(name, Directory.parse(data)) }
return_dir
end
end
class Parser
attr_reader :first_parts
attr_reader :second_parts
def initialize (parse_string)
@first_parts, @second_parts = Hash.new, Hash.new
parse(parse_string)
end
def parse(parse_string)
@string = parse_string
parse_helper(@first_parts)
parse_helper(@second_parts)
end
private
def parse_helper(part_colector)
part_count = @string.split(":")[0].to_i
@string = @string[ part_count.to_s.length+1 .. @string.length]
parse_split_parts(part_colector, part_count)
end
def parse_split_parts (part_colector, part_count)
return if part_count == 0
part_name, part_size = @string.split(":")[0], @string.split(":")[1].to_i
@string = @string[part_name.length + part_size.to_s.length + 2 .. @string.length]
part_colector[part_name] = @string[0..part_size - 1]
@string = @string[part_size..@string.length]
parse_split_parts(part_colector, part_count - 1)
end
end
end

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

.............F..............F..F..FFFF..FFFF

Failures:

  1) RBFS Directory serialization ::parse can parse directories recursively
     Failure/Error: expect(rbfs_directory['solution.rb'].data ).to eq :hidden
       
       expected: :hidden
            got: "hidden"
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,2 @@
       -:hidden
       +"hidden"
     # /tmp/d20141111-26053-muqrmo/spec.rb:133:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) RBFS File data type string can parse a string with colons
     Failure/Error: expect(file.data     ).to eq 'Hay :)'
       
       expected: "Hay :)"
            got: "Hay "
       
       (compared using ==)
     # /tmp/d20141111-26053-muqrmo/spec.rb:257:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) RBFS File data type symbol can be parsed
     Failure/Error: expect(file.data     ).to eq :hello
       
       expected: :hello
            got: "hello"
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,2 @@
       -:hello
       +"hello"
     # /tmp/d20141111-26053-muqrmo/spec.rb:276:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) RBFS File data type number can be parsed
     Failure/Error: expect(file.data     ).to eq 1234
       
       expected: 1234
            got: "1234"
       
       (compared using ==)
     # /tmp/d20141111-26053-muqrmo/spec.rb:295:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  5) RBFS File data type float number can be detected
     Failure/Error: expect(file.data_type).to eq :number
       
       expected: :number
            got: :nil
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,2 @@
       -:number
       +:nil
     # /tmp/d20141111-26053-muqrmo/spec.rb:304:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  6) RBFS File data type float number can be serialized
     Failure/Error: expect(file.serialize).to eq 'number:666.6'
       
       expected: "number:666.6"
            got: "nil:666.6"
       
       (compared using ==)
     # /tmp/d20141111-26053-muqrmo/spec.rb:308:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  7) RBFS File data type float number can be parsed
     Failure/Error: expect(file.data     ).to eq 3.14
       
       expected: 3.14
            got: "3.14"
       
       (compared using ==)
     # /tmp/d20141111-26053-muqrmo/spec.rb:314:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  8) RBFS File data type boolean true can be parsed
     Failure/Error: expect(file.data     ).to eq true
       
       expected: true
            got: "true"
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,2 @@
       -true
       +"true"
     # /tmp/d20141111-26053-muqrmo/spec.rb:334:in `block (6 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  9) RBFS File data type boolean false can be detected
     Failure/Error: expect(file.data_type).to eq :boolean
       
       expected: :boolean
            got: :nil
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,2 @@
       -:boolean
       +:nil
     # /tmp/d20141111-26053-muqrmo/spec.rb:342:in `block (6 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  10) RBFS File data type boolean false can be serialized
     Failure/Error: expect(file.serialize).to eq 'boolean:false'
       
       expected: "boolean:false"
            got: "nil:false"
       
       (compared using ==)
     # /tmp/d20141111-26053-muqrmo/spec.rb:347:in `block (6 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  11) RBFS File data type boolean false can be parsed
     Failure/Error: expect(file.data     ).to eq false
       
       expected: false
            got: "false"
       
       (compared using ==)
     # /tmp/d20141111-26053-muqrmo/spec.rb:353:in `block (6 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.04589 seconds
44 examples, 11 failures

Failed examples:

rspec /tmp/d20141111-26053-muqrmo/spec.rb:124 # RBFS Directory serialization ::parse can parse directories recursively
rspec /tmp/d20141111-26053-muqrmo/spec.rb:254 # RBFS File data type string can parse a string with colons
rspec /tmp/d20141111-26053-muqrmo/spec.rb:273 # RBFS File data type symbol can be parsed
rspec /tmp/d20141111-26053-muqrmo/spec.rb:292 # RBFS File data type number can be parsed
rspec /tmp/d20141111-26053-muqrmo/spec.rb:303 # RBFS File data type float number can be detected
rspec /tmp/d20141111-26053-muqrmo/spec.rb:307 # RBFS File data type float number can be serialized
rspec /tmp/d20141111-26053-muqrmo/spec.rb:311 # RBFS File data type float number can be parsed
rspec /tmp/d20141111-26053-muqrmo/spec.rb:331 # RBFS File data type boolean true can be parsed
rspec /tmp/d20141111-26053-muqrmo/spec.rb:340 # RBFS File data type boolean false can be detected
rspec /tmp/d20141111-26053-muqrmo/spec.rb:345 # RBFS File data type boolean false can be serialized
rspec /tmp/d20141111-26053-muqrmo/spec.rb:350 # RBFS File data type boolean false can be parsed

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

Яни обнови решението на 03.11.2014 08:26 (преди около 10 години)

+module RBFS
+ class File
+ attr :data, true
+ attr :data_type, true
+
+ def initialize (start_data = nil)
+ @data = start_data
+ set_data_type(start_data)
+ end
+
+ def data=(new_data)
+ @data = new_data
+ set_data_type(new_data)
+ end
+
+ def serialize
+ @data_type.to_s + ":" + @data.to_s
+ end
+
+ def File.parse(parse_string)
+ ret = File.new
+ ret.data = parse_string.split(":")[1]
+ ret.data_type = parse_string.split(":")[0].to_sym
+ ret
+ end
+
+ private
+
+ def set_data_type(start_data)
+ @data_type = :nil if start_data.is_a?( NilClass)
+ @data_type = :string if start_data.is_a?(String)
+ @data_type = :number if start_data.is_a?(Integer) || start_data.is_a?(Float)
+ @data_type = :symbol if start_data.is_a?(Symbol)
+ @data_type = :boolean if start_data.is_a?(TrueClass) || start_data.is_a?(FalseClass)
+ end
+ end
+
+ class Directory
+ attr :files, true
+ attr :directories, true
+
+ def initialize
+ @files = Hash.new
+ @directories = Hash.new
+ end
+
+ def add_file(file_name, file_data)
+ @files[file_name] = file_data
+ end
+
+ def add_directory(directory_name, directory_data = RBFS::Directory.new)
+ @directories[directory_name] = directory_data
+ end
+
+ def serialize
+ ret = @files.size.to_s.concat(":")
+ @files.each_pair{ |a, b|
+ ret << a << ":" << b.serialize.length.to_s << ":" << b.serialize }
+ ret<<@directories.size.to_s<<":"
+ @directories.each_pair{ | a, b |
+ ret << a << ":" << b.serialize.length.to_s << ":" << b.serialize }
+ ret
+ end
+
+ def [](index_name)
+ if @files[index_name] == nil
+ ret = @directories[index_name]
+ else ret = @files[index_name]
+ end
+ end
+
+ def Directory.parse( parse_string)
+ return_dir = RBFS::Directory.new
+ file_count = parse_string.split(":")[0].to_i
+ parse_string = parse_string[ file_count.to_s.length+1 .. parse_string.length]
+ parse_string = parse_read_files(parse_string,return_dir,file_count)
+ dir_count = parse_string.split(":")[0].to_i
+ parse_string = parse_string[ dir_count.to_s.length+1 .. parse_string.length]
+ parse_string = parse_read_directories(parse_string, return_dir, dir_count)
+ return_dir
+ end
+
+ private
+
+ def Directory.parse_read_files( string, dir, file_count)
+ return string if file_count==0
+ file_name, file_size = string.split(":")[0], string.split(":")[1].to_i
+ string = string[file_name.length + 1 + file_size.to_s.length + 1 .. string.length]
+ dir.add_file(file_name, File.parse(string[0..file_size - 1]))
+ string = parse_read_files(string[file_size..string.length], dir, file_count - 1)
+ end
+
+ def Directory.parse_read_directories(string, dir, dir_count)
+ return string if dir_count==0
+ dir_name, dir_size = string.split(":")[0] , string.split(":")[1].to_i
+ string = string[dir_name.length + 1 + dir_size.to_s.length + 1 .. string.length]
+ dir.add_directory(dir_name,Directory.parse(string[0..dir_size - 1]))
+ string = parse_read_directories(string[dir_size..string.length], dir, dir_count - 1)
+ end
+ end
+end

Ако е възможно може ли да ми дадете някой съвет отностно directory.parse?(разбира се в рамките на "подсказка") Защото тази част наистина ме затрудни и ми се иска да я направя по-добре, но не виждам вмомента как, имайки предвид, че едвам направих това сам.

Здравей :)

Ето няколко бързи съвета:

  • Първо, оправи си индентацията, много ми е трудно да прочета кода :)
  • Използвай case вместо многото if-ове. Подсказвам, че с case можеш да сравняваш класовете на обектите без методи като is_a?
  • attr_reader, attr_accessor и attr_writer вместо attr :method, true. По-ясно е. Аз например не съм сигурен какъв е вторият аргумент и трябва да ходя да чета документацията :)
  • Използвай do ... end за многоредови неща.
  • Методите parse_read_* са еднакви, с изключение на това дали създават директория или файл. Можеш ли да се сетиш как да ги обединиш - да извадиш логиката за създаване на самите файлове и директории и да ги сложиш в метода, който извиква parse_read_*.
  • [] може да се напише малко по-кратко, като използваш, че hash[key] връща nil за ключ, който го няма + определена логическа операция.

Опитай се да отделиш логиката по парсването от логиката на самата директория. Поне до колкото е възможно.

Например - създай си нов клас Parser, един от методите на който може да е parse_array или parse_list. Този метод може да се използва в Directory.parse, за да му дава двойки - име и стринг - това, което ти трябва, за да създадеш файл или директория и да я добавиш в текущата. Този метод ще го извикваш два пъти - за файловете и за директориите. Полезно е, освен това, този новият клас да не е само с класови методи, а да пази състояние, така че да не се налага да ти връща и остатъка от стринга.

Ако още имаш въпроси или не разбираш нещо, което съм написал - питай :)

Страхотно, точно от каквото се нужаех за по-добро решение. Благодаря много. За жалост през седмицата няма да имам възможност да подобря решението, затова ще го модифицирам чак в края на седмицата.

П.П. Индентацията се е получила основно от самокопиращите се табулации при писането на кода и след това от копирането му като "решение". Много неприятно.

Яни обнови решението на 04.11.2014 11:55 (преди около 10 години)

module RBFS
class File
- attr :data, true
- attr :data_type, true
+ attr_accessor :data
+ attr_accessor :data_type
def initialize (start_data = nil)
@data = start_data
- set_data_type(start_data)
+ set_data_type(start_data)
end
- def data=(new_data)
- @data = new_data
- set_data_type(new_data)
- end
+ def data=(new_data)
+ @data = new_data
+ set_data_type(new_data)
+ end
- def serialize
- @data_type.to_s + ":" + @data.to_s
- end
+ def data_type=(new_type)
+ @data_type = new_type
+ case @new_type
+ when :nil then @data = nil
+ when :string then @data = @data.to_s
+ when :number then @data = @data.to_f
+ when :symbol then @data = @data.to_sym
+ when :boolean then @data = @data == "true"
+ end
+ end
- def File.parse(parse_string)
- ret = File.new
- ret.data = parse_string.split(":")[1]
- ret.data_type = parse_string.split(":")[0].to_sym
- ret
- end
+ def serialize
+ @data_type.to_s + ":" + @data.to_s
+ end
+ def File.parse(parse_string)
+ ret = File.new
+ ret.data = parse_string.split(":")[1]
+ ret.data_type = parse_string.split(":")[0].to_sym
+ ret
+ end
+
private
def set_data_type(start_data)
- @data_type = :nil if start_data.is_a?( NilClass)
- @data_type = :string if start_data.is_a?(String)
- @data_type = :number if start_data.is_a?(Integer) || start_data.is_a?(Float)
- @data_type = :symbol if start_data.is_a?(Symbol)
- @data_type = :boolean if start_data.is_a?(TrueClass) || start_data.is_a?(FalseClass)
+ case start_data
+ when NilClass then @data_type = :nil
+ when String then @data_type = :string
+ when Integer || Float then @data_type = :number
+ when Symbol then @data_type = :symbol
+ when TrueClass || FalseClass then @data_type = :boolean
+ end
end
end
class Directory
attr :files, true
attr :directories, true
- def initialize
- @files = Hash.new
- @directories = Hash.new
- end
+ def initialize
+ @files = Hash.new
+ @directories = Hash.new
+ end
- def add_file(file_name, file_data)
+ def add_file(file_name, file_data)
@files[file_name] = file_data
- end
+ end
def add_directory(directory_name, directory_data = RBFS::Directory.new)
@directories[directory_name] = directory_data
- end
+ end
- def serialize
- ret = @files.size.to_s.concat(":")
- @files.each_pair{ |a, b|
- ret << a << ":" << b.serialize.length.to_s << ":" << b.serialize }
- ret<<@directories.size.to_s<<":"
- @directories.each_pair{ | a, b |
- ret << a << ":" << b.serialize.length.to_s << ":" << b.serialize }
- ret
- end
+ def serialize
+ ret = @files.size.to_s.concat(":")
+ @files.each_pair{ |a, b|
+ ret << a << ":" << b.serialize.length.to_s << ":" << b.serialize }
+ ret << @directories.size.to_s << ":"
+ @directories.each_pair{ | a, b | #Skeptic:Space=symbol, Style Guide align conflict
+ ret << a << ":" << b.serialize.length.to_s << ":" << b.serialize }
+ ret
+ end
- def [](index_name)
- if @files[index_name] == nil
- ret = @directories[index_name]
- else ret = @files[index_name]
- end
- end
+ def [](index_name)
+ ret = @files[index_name] || @directories[index_name]
+ end
- def Directory.parse( parse_string)
- return_dir = RBFS::Directory.new
- file_count = parse_string.split(":")[0].to_i
- parse_string = parse_string[ file_count.to_s.length+1 .. parse_string.length]
- parse_string = parse_read_files(parse_string,return_dir,file_count)
- dir_count = parse_string.split(":")[0].to_i
- parse_string = parse_string[ dir_count.to_s.length+1 .. parse_string.length]
- parse_string = parse_read_directories(parse_string, return_dir, dir_count)
- return_dir
- end
+ def Directory.parse( parse_string)
+ return_dir = RBFS::Directory.new
+ parser = Parser.new(parse_string)
+ parser.first_parts.each_pair{ | name , data |
+ return_dir.add_file(name, File.parse(data)) }
+ parser.second_parts.each_pair{ | name , data | #Same problem with Skeptic
+ return_dir.add_directory(name, Directory.parse(data)) }
+ return_dir
+ end
- private
+ end
+ class Parser
+ attr_reader :first_parts
+ attr_reader :second_parts
- def Directory.parse_read_files( string, dir, file_count)
- return string if file_count==0
- file_name, file_size = string.split(":")[0], string.split(":")[1].to_i
- string = string[file_name.length + 1 + file_size.to_s.length + 1 .. string.length]
- dir.add_file(file_name, File.parse(string[0..file_size - 1]))
- string = parse_read_files(string[file_size..string.length], dir, file_count - 1)
- end
+ def initialize (parse_string)
+ @first_parts, @second_parts = Hash.new, Hash.new
+ parse(parse_string)
+ end
- def Directory.parse_read_directories(string, dir, dir_count)
- return string if dir_count==0
- dir_name, dir_size = string.split(":")[0] , string.split(":")[1].to_i
- string = string[dir_name.length + 1 + dir_size.to_s.length + 1 .. string.length]
- dir.add_directory(dir_name,Directory.parse(string[0..dir_size - 1]))
- string = parse_read_directories(string[dir_size..string.length], dir, dir_count - 1)
- end
+ def parse(parse_string)
+ @string = parse_string
+ parse_helper(@first_parts)
+ parse_helper(@second_parts)
+ end
+
+ private
+
+ def parse_helper(part_colector)
+ part_count = @string.split(":")[0].to_i
+ @string = @string[ part_count.to_s.length+1 .. @string.length]
+ parse_split_parts(part_colector, part_count)
+ end
+
+ def parse_split_parts (part_colector, part_count)
+ return if part_count == 0
+ part_name, part_size = @string.split(":")[0], @string.split(":")[1].to_i
+ @string = @string[part_name.length + part_size.to_s.length + 2 .. @string.length]
+ part_colector[part_name] = @string[0..part_size - 1]
+ @string = @string[part_size..@string.length]
+ parse_split_parts(part_colector, part_count - 1)
+ end
end
end