Решение на Четвърта задача от Герасим Станчев

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

Към профила на Герасим Станчев

Резултати

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

Код

module UI
def self.set_style_to_segment(segment, style)
if style.nil? or segment.frozen?
segment
else
segment.method(style).call
end
end
class TextScreen
def self.draw
@components = []
@components_added_count = 0
instance_eval &Proc.new
@components.join
end
def self.label(text:, style: nil, border: nil)
text = "#{border}#{text}#{border}"
text = text.method(style).call.freeze unless style.nil?
@components << text
@components_added_count += 1
end
def self.vertical(border: nil, style: nil)
@components_added_count = 0
checked_components_count = @components.size - @components_added_count
yield
@components.map! { |segment| UI::set_style_to_segment(segment, style) }
alignment = @components[checked_components_count.. - 1]
.group_by(&:size).max.first
set_vertical_alignment(alignment, border)
end
def self.set_vertical_alignment(alignment, border)
checked_components_count = @components.size - @components_added_count
@components[checked_components_count.. - 1].each do |segment|
segment.prepend("#{border}") << "#{border}\n"
.rjust(alignment - segment.size + border.to_s.size * 2 + 1)
end
end
def self.horizontal(border: nil, style: nil)
@components_added_count = 0
components_copy = @components.dup
yield
@components.map! { |segment| UI::set_style_to_segment(segment, style) }
components_copy = [(@components - components_copy).join]
set_horizontal_alignment(components_copy, border)
end
def self.set_horizontal_alignment(components_copy, border)
alignment = @components.group_by(&:size).max.first
1.upto(@components_added_count) { |index| @components.delete_at(-1) }
@components += components_copy
@components.last.prepend("#{border}") << "#{border}"
.rjust(alignment - @components.last.size + border.to_s.size * 2 - 1)
end
end
end

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

...F.F.F.F.

Failures:

  1) Command Line Toolkit handles complex group nestings
     Failure/Error: expect do
       expected #<Proc:0xb9b1b1d8@/tmp/d20141126-26053-v9v7gv/spec.rb:56> to render as "      123\n        45\n         6\n      7\n"
     # /tmp/d20141126-26053-v9v7gv/spec.rb:56:in `block (2 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) Command Line Toolkit handles borders correctly in complex group nestings
     Failure/Error: expect do
       expected #<Proc:0xb9b122f4@/tmp/d20141126-26053-v9v7gv/spec.rb:99> to render as "      |||1||2|||3|       |||\n      ||      |||4|||5||||||\n      ||      ||   ||6||||||\n      ||7|                 |\n"
     # /tmp/d20141126-26053-v9v7gv/spec.rb:99:in `block (2 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) Command Line Toolkit propagates upcase to child components
     Failure/Error: expect do
       expected #<Proc:0xb9aeace0@/tmp/d20141126-26053-v9v7gv/spec.rb:137> to render as "      someveryINTERESTINGget it?\n              TEXTGOES       \n                  HERE       \n"
     # /tmp/d20141126-26053-v9v7gv/spec.rb:137:in `block (2 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) Command Line Toolkit propagates downcase to child components
     Failure/Error: expect do
       expected #<Proc:0xb9ad91fc@/tmp/d20141126-26053-v9v7gv/spec.rb:172> to render as "      SOMEVERYinterestingGET IT?\n              textgoes       \n                  here       \n"
     # /tmp/d20141126-26053-v9v7gv/spec.rb:172:in `block (2 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.02311 seconds
11 examples, 4 failures

Failed examples:

rspec /tmp/d20141126-26053-v9v7gv/spec.rb:55 # Command Line Toolkit handles complex group nestings
rspec /tmp/d20141126-26053-v9v7gv/spec.rb:98 # Command Line Toolkit handles borders correctly in complex group nestings
rspec /tmp/d20141126-26053-v9v7gv/spec.rb:136 # Command Line Toolkit propagates upcase to child components
rspec /tmp/d20141126-26053-v9v7gv/spec.rb:171 # Command Line Toolkit propagates downcase to child components

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

Герасим обнови решението на 21.11.2014 16:30 (преди около 10 години)

+module UI
+ class TextScreen
+ def self.label(text:, style: nil, border: nil)
+ text = "#{border}#{text}#{border}"
+ text = text.method(style).call.freeze unless style.nil?
+ @components << text
+ @counter += 1
+ end
+
+ def self.vertical(border: nil, style: nil)
+ yield
+ stowage = @components.group_by(&:size).max.last[0].size.to_i
+ @components.each do |word|
+ word.prepend("#{border}") << "#{border}\n"
+ .rjust(stowage - word.size + border.to_s.length + 2)
+ end
+ end
+
+ def self.horizontal(style: nil, border: nil)
+ @counter, components_copy = 0, @components.dup
+ yield
+ @components.collect! do |word|
+ set_style_to_word(word, style)
+ end
+ stowage = @components.group_by(&:size).max.last[0].size.to_i
+ horizontal_stowage(components_copy, border, stowage)
+ end
+
+ def self.horizontal_stowage(components_copy, border, stowage)
+ components_copy = [(@components - components_copy).join]
+ 1.upto(@counter) { |index| @components.delete_at(-1) }
+ @components += components_copy
+ @components.each do |word|
+ word.prepend("#{border}") << "#{border}"
+ .rjust(stowage - word.size + border.to_s.length + 1)
+ end
+ end
+
+ def self.draw
+ @components = []
+ @counter = 0
+ instance_eval &Proc.new
+ @components.join
+ end
+
+ def self.set_style_to_word(word, style)
+ return word if style.nil? or word.frozen?
+ word = word.method(style).call
+ end
+ end
+end

Герасим обнови решението на 24.11.2014 04:24 (преди около 10 години)

module UI
+ def self.set_style_to_segment(segment, style)
+ if style.nil? or segment.frozen?
+ segment
+ else
+ segment.method(style).call
+ end
+ end
+
class TextScreen
+ def self.draw
+ @components = []
+ @components_added_count = 0
+ instance_eval &Proc.new
+ @components.join
+ end
+
def self.label(text:, style: nil, border: nil)
text = "#{border}#{text}#{border}"
text = text.method(style).call.freeze unless style.nil?
@components << text
- @counter += 1
+ @components_added_count += 1
end
def self.vertical(border: nil, style: nil)
+ @components_added_count = 0
+ checked_components_count = @components.size - @components_added_count
yield
- stowage = @components.group_by(&:size).max.last[0].size.to_i
- @components.each do |word|
- word.prepend("#{border}") << "#{border}\n"
- .rjust(stowage - word.size + border.to_s.length + 2)
- end
+ @components.map! { |segment| UI::set_style_to_segment(segment, style) }
+ alignment = @components[checked_components_count.. - 1]
+ .group_by(&:size).max.first
+ set_vertical_alignment(alignment, border)
end
- def self.horizontal(style: nil, border: nil)
- @counter, components_copy = 0, @components.dup
- yield
- @components.collect! do |word|
- set_style_to_word(word, style)
+ def self.set_vertical_alignment(alignment, border)
+ checked_components_count = @components.size - @components_added_count
+ @components[checked_components_count.. - 1].each do |segment|
+ segment.prepend("#{border}") << "#{border}\n"
+ .rjust(alignment - segment.size + border.to_s.size * 2 + 1)
end
- stowage = @components.group_by(&:size).max.last[0].size.to_i
- horizontal_stowage(components_copy, border, stowage)
end
- def self.horizontal_stowage(components_copy, border, stowage)
+ def self.horizontal(border: nil, style: nil)
+ @components_added_count = 0
+ components_copy = @components.dup
+ yield
+ @components.map! { |segment| UI::set_style_to_segment(segment, style) }
components_copy = [(@components - components_copy).join]
- 1.upto(@counter) { |index| @components.delete_at(-1) }
- @components += components_copy
- @components.each do |word|
- word.prepend("#{border}") << "#{border}"
- .rjust(stowage - word.size + border.to_s.length + 1)
- end
+ set_horizontal_alignment(components_copy, border)
end
- def self.draw
- @components = []
- @counter = 0
- instance_eval &Proc.new
- @components.join
+ def self.set_horizontal_alignment(components_copy, border)
+ alignment = @components.group_by(&:size).max.first
+ 1.upto(@components_added_count) { |index| @components.delete_at(-1) }
+ @components += components_copy
+ @components.last.prepend("#{border}") << "#{border}"
+ .rjust(alignment - @components.last.size + border.to_s.size * 2 - 1)
end
-
- def self.set_style_to_word(word, style)
- return word if style.nil? or word.frozen?
- word = word.method(style).call
- end
end
-end
+end

Прегледай примерите, които сме дискутирали в темата във форума.

instance_eval &Proc.new за мен е доста по-неясно от това да вземеш блока и да го instance_eval-неш.

Защо set_style_to_segment е в UI?

Прилагането на стил ми се струва дублицирано в UI.set_style_to_segment и UI::TextScreen.label. Не може ли да се централизира? Защо ти се налага да freeze-ваш текстовете? Не можеш ли да контролираш начина/реда за прилагане на стилове по друг начин?

До колкото разбирам методите set_vertical_alignment и set_horizontal_alignment също са част от DSL-а. Тоест, мога да ги извикам в блока, който описва изгледа. Можеш ли да ги премахнеш, оставяйки само horizontal, vertical и label като част от DSL-а?

Предполагам, че имаш предвид въпроса на Александър, за двата последователни vertical блока. Не разбирам защо са на един ред, при положение, че се изпълняват отделно.

За instance_eval - ок, сългасен съм. Трябва ли да правя проверка дали е подаден блок? Т.е. винаги ли ще се подава блок?

Мога да изградя някаква структурна последователност (и безуспешно опитах да го сторя), но избрах този вариант. Разбирам, че тази употреба на freeze не е най-адекватната, но мисля, че върши страхотна работа и покрива точно изискванията. Освен това си мислех дали да не изведа инстанционна променлива @style, която да се променя за всеки блок, а не да се извиква за всеки блок, но реших, че така е по-консистентно.

Т.е. да изведа тези два метода в отделен модул?

Блоковете не се "изпълняват". Те дефинират структурата на интерфейса, който ти трябва да изпълниш така че да изглежда по желания начин. Двата vertical блока са на едно и също ниво тъй като са вложени в "анонимен" horizontal блок (по подразбиране нещата в TextScreen се подреждат хоризонтално).

Да, винаги ще се подава блок.

Т.е. когато в блока на horizontal примерно съм използвал нещо различно от horizontal, vertical и label да ми гърми с NameError. :)