Решение на Четвърта задача от Екатерина Горанова

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

Към профила на Екатерина Горанова

Резултати

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

Код

module UI
class Element
def initialize(style:nil, border:nil)
@style = style if style
@border = border
end
def add_style(style)
@style = style unless @style
end
def create_border(text)
"#{@border}#{text}#{@border}"
end
end
class Label < Element
def initialize(text:, style:nil, border:nil)
@text = text
super style:style, border:border
end
def apply_style
@style ? @text.send(@style) : @text
end
def to_s
create_border apply_style
end
end
class Group < Element
def initialize(style:nil, border:nil, &block)
@elements = []
instance_eval(&block)
super style:style, border:border, &block
end
def label(text:, style:nil, border:nil)
@elements << Label.new(text:text, style:style, border:border)
end
def horizontal(style:nil, border:nil, &block)
@elements << HorizontalGroup.new(style:style, border:border, &block)
end
def vertical(style:nil, border:nil, &block)
@elements << VerticalGroup.new(style:style, border:border, &block)
end
def apply_style
@elements.each do |element|
element.add_style @style
element.apply_style
end
end
end
class HorizontalGroup < Group
def to_s
create_border @elements.each(&:apply_style).map(&:to_s).join("")
end
end
class VerticalGroup < Group
def create_border(text)
lines = text.split("\n")
max_length = lines.max_by(&:length).length
lines.map { |line| super(line.ljust(max_length)) }.join("\n")
end
def to_s
create_border @elements.each(&:apply_style).map(&:to_s).join("\n")
end
end
class TextScreen
def self.draw(&block)
HorizontalGroup.new(&block)
end
end
end

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

...F.F.F.F.

Failures:

  1) Command Line Toolkit handles complex group nestings
     Failure/Error: expect do
       expected #<Proc:0xb8e060c4@/tmp/d20141126-26053-fmwjs8/spec.rb:56> to render as "      123\n        45\n         6\n      7\n"
     # /tmp/d20141126-26053-fmwjs8/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:0xb8de81c8@/tmp/d20141126-26053-fmwjs8/spec.rb:99> to render as "      |||1||2|||3|       |||\n      ||      |||4|||5||||||\n      ||      ||   ||6||||||\n      ||7|                 |\n"
     # /tmp/d20141126-26053-fmwjs8/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:0xb8dd52e4@/tmp/d20141126-26053-fmwjs8/spec.rb:137> to render as "      someveryINTERESTINGget it?\n              TEXTGOES       \n                  HERE       \n"
     # /tmp/d20141126-26053-fmwjs8/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:0xb8db3680@/tmp/d20141126-26053-fmwjs8/spec.rb:172> to render as "      SOMEVERYinterestingGET IT?\n              textgoes       \n                  here       \n"
     # /tmp/d20141126-26053-fmwjs8/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.0236 seconds
11 examples, 4 failures

Failed examples:

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

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

Екатерина обнови решението на 21.11.2014 07:48 (преди около 10 години)

+module UI
+ class Element
+ attr_reader :style
+
+ def initialize(style:nil, border:nil)
+ @style = style if style
+ @border = border
+ end
+
+ def add_style(style)
+ @style = style unless @style
+ end
+
+ def create_border(text)
+ "#{@border}#{text}#{@border}"
+ end
+ end
+
+ class Label < Element
+ def initialize(text:, style:nil, border:nil)
+ @text = text
+ super style:style, border:border
+ end
+
+ def apply_style
+ @style ? @text.send(@style) : @text
+ end
+
+ def to_s
+ create_border apply_style
+ end
+ end
+
+ class Horizontal < Element
+ def initialize(style:nil, border:nil)
+ @content = []
+ super style:style, border:border
+ end
+
+ def label(text:, style:nil, border:nil)
+ @content << Label.new(text:text, style:style, border:border)
+ @content.last
+ end
+
+ def horizontal(style:nil, border:nil, &block)
+ horizontal = Horizontal.new(style:style, border:border)
+ horizontal.instance_eval(&block)
+ @content << horizontal
+ horizontal
+ end
+
+ def vertical(style:nil, border:nil, &block)
+ vertical = Vertical.new(style:style, border:border)
+ vertical.instance_eval(&block)
+ @content << vertical
+ vertical
+ end
+
+ def apply_style
+ @content.each do |element|
+ element.add_style @style
+ element.apply_style
+ end
+ end
+
+ def to_s
+ create_border @content.each(&:apply_style).map(&:to_s).join('')
+ end
+ end
+
+ class Vertical < Horizontal
+ def create_border(text)
+ lines = text.split("\n")
+ max_length = lines.max_by(&:length).length
+ lines.map { |line| super(line.ljust(max_length)) }.join("\n")
+ end
+
+ def to_s
+ create_border @content.each(&:apply_style).map(&:to_s).join("\n")
+ end
+ end
+
+ class TextScreen
+ def self.draw(&block)
+ screen = Horizontal.new
+ screen.instance_eval(&block)
+ screen
+ end
+ end
+end

Не ми допада това, че Vertical надледява Horizontal само за да получи функционалността за добавяне на компоненти. Можеш ли да я изнесеш и да я използваш и на двете места?

Какво те притеснява в методите horizontal и vertical? Защо се налага те да връщат обекта, който създават? Можеш да подадеш блока, който получаваш на съответния обект (Horizontal / Vertical) и да instance_eval-неш в initialize метода. Така кода в тези два метода ще се сведе до един ред, който добавя елемент в @content.

Името @content не ми харесва много. Помисли за нещо по-удачно. Също така Horizontal и Vertical са прилагателни. Можеш ли да ги комбинираш с някакво съществително? Не е нужно да са 1:1 с имената на методите от DSL-а и по мое мнение е по-добре името на клас да включва съществително (понякога може и глагол).

Помисли за това какъв трябва да е резултата от horizontal блок, в който имаш вложен vertical на някоя от междинните позиции (не първа). Примерно:

horizontal do
  label '1'
  vertical do 
    label '2'
    label '3'
  end
end

:)

Екатерина обнови решението на 26.11.2014 10:49 (преди почти 10 години)

module UI
class Element
- attr_reader :style
-
def initialize(style:nil, border:nil)
@style = style if style
@border = border
end
def add_style(style)
@style = style unless @style
end
def create_border(text)
"#{@border}#{text}#{@border}"
end
end
class Label < Element
def initialize(text:, style:nil, border:nil)
@text = text
super style:style, border:border
end
def apply_style
@style ? @text.send(@style) : @text
end
def to_s
create_border apply_style
end
end
- class Horizontal < Element
- def initialize(style:nil, border:nil)
- @content = []
- super style:style, border:border
+ class Group < Element
+ def initialize(style:nil, border:nil, &block)
+ @elements = []
+ instance_eval(&block)
+ super style:style, border:border, &block
end
def label(text:, style:nil, border:nil)
- @content << Label.new(text:text, style:style, border:border)
- @content.last
+ @elements << Label.new(text:text, style:style, border:border)
end
def horizontal(style:nil, border:nil, &block)
- horizontal = Horizontal.new(style:style, border:border)
- horizontal.instance_eval(&block)
- @content << horizontal
- horizontal
+ @elements << HorizontalGroup.new(style:style, border:border, &block)
end
def vertical(style:nil, border:nil, &block)
- vertical = Vertical.new(style:style, border:border)
- vertical.instance_eval(&block)
- @content << vertical
- vertical
+ @elements << VerticalGroup.new(style:style, border:border, &block)
end
def apply_style
- @content.each do |element|
+ @elements.each do |element|
element.add_style @style
element.apply_style
end
end
+ end
+ class HorizontalGroup < Group
def to_s
- create_border @content.each(&:apply_style).map(&:to_s).join('')
+ create_border @elements.each(&:apply_style).map(&:to_s).join("")
end
end
- class Vertical < Horizontal
+ class VerticalGroup < Group
def create_border(text)
lines = text.split("\n")
max_length = lines.max_by(&:length).length
lines.map { |line| super(line.ljust(max_length)) }.join("\n")
end
def to_s
- create_border @content.each(&:apply_style).map(&:to_s).join("\n")
+ create_border @elements.each(&:apply_style).map(&:to_s).join("\n")
end
end
class TextScreen
def self.draw(&block)
- screen = Horizontal.new
- screen.instance_eval(&block)
- screen
+ HorizontalGroup.new(&block)
end
end
end