Решение на Четвърта задача от Бисер Кръстев

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

Към профила на Бисер Кръстев

Резултати

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

Код

module UI
# the main UI API
class TextScreen
def self.draw(&block)
# base for the "stack"
@result = TextStructure.new
# call the block which modifies the @result
class_eval &block if block_given?
# finally get the whole result
@result.evaluate_self
end
def self.label(text:, border: nil, style: nil)
# take the input and give it borders
my_result = "#{border}#{text}#{border}"
# apply a style overriding the ones in the stack if needed
StyleManager.push style
my_result = StyleManager.apply_style my_result
StyleManager.pop
# this is where actual adding of text to the result happens
@result.add_text my_result
end
def self.horizontal(border: nil, style: nil, &block)
# create a new "level" in the "stack"
@result = @result.create_subtext
# call the block if such is given
StyleManager.push style
block.call if block_given?
StyleManager.pop
@result.text = "#{border}#{@result.text}#{border}"
# evaluate this result, glue it to the parent and go back in the "stack"
@result = @result.evaluate_self
end
def self.vertical(border: nil, style: nil, &block)
# create a new "level" in the "stack"
@result = @result.create_subtext true
# call the block if such is given
StyleManager.push style
block.call if block_given?
StyleManager.pop
# put borders
@result.text = border_vertical @result.text, border
# evaluate this result, glue it to the parent and go back in the "stack"
@result = @result.evaluate_self
end
private
def self.border_vertical(text, border = nil)
# calculate maximum length so borders can be put correctly
lines = @result.text.lines.map { |l| l.rstrip }
length = lines.max_by { |l| l.length }.length
lines.map { |l| "#{border}#{l.ljust length}#{border}" }.join "\n"
end
end
# many instances of this class create a stack-like structure
class TextStructure
# the text of the instance
attr_accessor :text
# instance of TextStructure (the stack-like structure)
attr_accessor :subtext
# each instance has a parent, except the first one
attr_accessor :parent
# whether to put a new line after each text adding in the subtext
attr_accessor :vertical
def initialize(parent = nil, vertical = false)
@parent = parent
@subtext = nil
@text = ""
@vertical = vertical
end
def add_text(text)
@text += text
@text += "\n" if @vertical
@text
end
# creates a subtext and returns it so it can be assigned to @result
# the global @result in TextScreen must be evaluated
# after adding text is finished to return to this node
def create_subtext(vertical = false)
@subtext = TextStructure.new self, vertical
end
# this is not needed actually, but it's here, get used to it (:
def evaluate_subtext
@text += @subtext.text
@subtext = nil
end
# adds this text to the parent's text
# clears the subtext of the parent
# and returns the parent so it can be assigned to @result
def evaluate_self
if not @parent then return @text end
@parent.text += @text
@parent.text += "\n" if @parent.vertical
@parent.subtext = nil
@parent
end
end
# a stack-like structure for storing the styles
# reading the top element "stack" is handled in a special way
class StyleManager
def self.initialize
@styles_stack = []
end
def self.push(style)
@styles_stack = [] if not defined? @styles_stack
@styles_stack.push style
end
def self.apply_style(text)
if not defined? @styles_stack then @styles_stack = [] end
# drop through all nils
style = @styles_stack.reverse.to_enum.find { |i| i }
# apply the style and return
case style
when :upcase then text.upcase
when :downcase then text.downcase
else text
end
end
def self.pop
@styles_stack = [] if not defined? @styles_stack
@styles_stack.pop
end
end
end

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

...F.F.F.F.

Failures:

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

Failed examples:

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

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

Бисер обнови решението на 26.11.2014 08:13 (преди почти 10 години)

+module UI
+ class TextScreen
+ def self.draw(&block)
+ # base for the "stack"
+ @result = TextStructure.new
+ # call the block which modifies the @result
+ block.call if block_given?
+ # finally get the whole result
+ @result.eval_self
+ end
+
+ def self.label(text:, border: nil, style: nil)
+ # take the input and give it borders
+ my_result = "#{border}#{text}#{border}"
+ # apply a style overriding the ones in the stack if needed
+ my_result = StyleManager.apply_style(my_result, style)
+ # this is where actual adding of text to the result happens
+ @result.add_text my_result
+ end
+
+ def self.horizontal(border: nil, style: nil, &block)
+ # create a new "level" in the "stack"
+ @result = @result.create_subtext
+ # call the block if such is given
+ block.call if block_given?
+ # evaluate this result, glue it to the parent and go back in the "stack"
+ @result = @result.eval_self
+ end
+
+ def self.vertical(border: nil, style: nil, &block)
+ # create a new "level" in the "stack"
+ @result = @result.create_subtext
+ # call the block if such is given
+ block.call if block_given?
+ # calculate maximum length so borders can be put correctly
+ length = @result.text.each_line.max { |l| l.length }.length
+ # put borders
+ @result.text.each_line { |l| l = "#{border}#{l.ljust! length}#{border}" }
+ # evaluate this result, glue it to the parent and go back in the "stack"
+ @result = @result.eval_self
+ end
+ end
+
+ # many instances of this class create a stack-like structure
+ class TextStructure
+ # the text of the instance
+ attr_accessor :text
+ # instance of TextStructure (the stack-like structure)
+ attr_accessor :subtext
+ # each instance has a parent, except the first one
+ attr_accessor :parent
+
+ def initialize(parent = nil)
+ @parent = parent
+ end
+
+ def add_text(text)
+ @text += text
+ end
+
+ # creates a subtext and returns it so it can be assigned to @result
+ # the global @result in TextScreen must be evaluated
+ # after adding text is finished to return to this node
+ def create_subtext
+ @subtext = TextStructure.new self
+ end
+
+ # this is not needed actually, but it's here, get used to it (:
+ def evaluate_subtext
+ @text += @subtext.text
+ @subtext = nil
+ end
+
+ # adds this text to the parent's text
+ # clears the subtext of the parent
+ # and returns the parent so it can be assigned to @result
+ def evaluate_self
+ if not @parent then @text end
+ @parent.text += @text
+ @parent.subtext = nil
+ @parent
+ end
+ end
+
+ # a stack-like structure for storing the styles
+ # reading the top element "stack" is handled in a special way
+ class StyleManager
+ def self.initialize
+ @styles_stack = []
+ end
+
+ def self.push(style)
+ @styles_stack = [] if not defined? @styles_stack
+ @styles_stack.push style
+ end
+
+ def self.apply_style(text, style = nil)
+ if not defined? @styles_stack then @styles_stack = [] end
+ # drop through all nils
+# style = @styles_stack.reverse.drop_while { |i| not i }.first if not style
+ # apply the style and return
+ case style
+ when :upcase then text.upcase
+ when :downcase then text.downcase
+ else text
+ end
+ end
+
+ def self.pop
+ @styles_stack = [] if not defined? @styles_stack
+ @styles_stack.pop
+ end
+ end
+end

Бисер обнови решението на 26.11.2014 08:30 (преди почти 10 години)

module UI
class TextScreen
def self.draw(&block)
# base for the "stack"
@result = TextStructure.new
# call the block which modifies the @result
- block.call if block_given?
+ instance_eval "block.call" if block_given?
# finally get the whole result
@result.eval_self
end
def self.label(text:, border: nil, style: nil)
# take the input and give it borders
my_result = "#{border}#{text}#{border}"
# apply a style overriding the ones in the stack if needed
- my_result = StyleManager.apply_style(my_result, style)
+ StyleManager.push style
+ my_result = StyleManager.apply_style my_result
+ StyleManager.pop
# this is where actual adding of text to the result happens
@result.add_text my_result
end
def self.horizontal(border: nil, style: nil, &block)
# create a new "level" in the "stack"
@result = @result.create_subtext
# call the block if such is given
block.call if block_given?
# evaluate this result, glue it to the parent and go back in the "stack"
@result = @result.eval_self
end
def self.vertical(border: nil, style: nil, &block)
# create a new "level" in the "stack"
@result = @result.create_subtext
# call the block if such is given
block.call if block_given?
# calculate maximum length so borders can be put correctly
length = @result.text.each_line.max { |l| l.length }.length
# put borders
@result.text.each_line { |l| l = "#{border}#{l.ljust! length}#{border}" }
# evaluate this result, glue it to the parent and go back in the "stack"
@result = @result.eval_self
end
end
# many instances of this class create a stack-like structure
class TextStructure
# the text of the instance
attr_accessor :text
# instance of TextStructure (the stack-like structure)
attr_accessor :subtext
# each instance has a parent, except the first one
attr_accessor :parent
def initialize(parent = nil)
@parent = parent
end
def add_text(text)
@text += text
end
# creates a subtext and returns it so it can be assigned to @result
# the global @result in TextScreen must be evaluated
# after adding text is finished to return to this node
def create_subtext
@subtext = TextStructure.new self
end
# this is not needed actually, but it's here, get used to it (:
def evaluate_subtext
@text += @subtext.text
@subtext = nil
end
# adds this text to the parent's text
# clears the subtext of the parent
# and returns the parent so it can be assigned to @result
def evaluate_self
if not @parent then @text end
@parent.text += @text
@parent.subtext = nil
@parent
end
end
# a stack-like structure for storing the styles
# reading the top element "stack" is handled in a special way
class StyleManager
def self.initialize
@styles_stack = []
end
def self.push(style)
@styles_stack = [] if not defined? @styles_stack
@styles_stack.push style
end
- def self.apply_style(text, style = nil)
+ def self.apply_style(text)
if not defined? @styles_stack then @styles_stack = [] end
# drop through all nils
-# style = @styles_stack.reverse.drop_while { |i| not i }.first if not style
+ style = @styles_stack.reverse.first { |i| ! i }
# apply the style and return
case style
when :upcase then text.upcase
when :downcase then text.downcase
else text
end
end
def self.pop
@styles_stack = [] if not defined? @styles_stack
@styles_stack.pop
end
end
end

Бисер обнови решението на 26.11.2014 13:45 (преди почти 10 години)

module UI
+ # the main UI API
class TextScreen
def self.draw(&block)
# base for the "stack"
@result = TextStructure.new
# call the block which modifies the @result
- instance_eval "block.call" if block_given?
+ class_eval &block if block_given?
# finally get the whole result
- @result.eval_self
+ @result.evaluate_self
end
def self.label(text:, border: nil, style: nil)
# take the input and give it borders
my_result = "#{border}#{text}#{border}"
# apply a style overriding the ones in the stack if needed
StyleManager.push style
my_result = StyleManager.apply_style my_result
StyleManager.pop
# this is where actual adding of text to the result happens
@result.add_text my_result
end
def self.horizontal(border: nil, style: nil, &block)
# create a new "level" in the "stack"
@result = @result.create_subtext
# call the block if such is given
+ StyleManager.push style
block.call if block_given?
+ StyleManager.pop
+ @result.text = "#{border}#{@result.text}#{border}"
# evaluate this result, glue it to the parent and go back in the "stack"
- @result = @result.eval_self
+ @result = @result.evaluate_self
end
def self.vertical(border: nil, style: nil, &block)
# create a new "level" in the "stack"
- @result = @result.create_subtext
+ @result = @result.create_subtext true
# call the block if such is given
+ StyleManager.push style
block.call if block_given?
- # calculate maximum length so borders can be put correctly
- length = @result.text.each_line.max { |l| l.length }.length
+ StyleManager.pop
# put borders
- @result.text.each_line { |l| l = "#{border}#{l.ljust! length}#{border}" }
+ @result.text = border_vertical @result.text, border
# evaluate this result, glue it to the parent and go back in the "stack"
- @result = @result.eval_self
+ @result = @result.evaluate_self
end
+
+ private
+
+ def self.border_vertical(text, border = nil)
+ # calculate maximum length so borders can be put correctly
+ lines = @result.text.lines.map { |l| l.rstrip }
+ length = lines.max_by { |l| l.length }.length
+ lines.map { |l| "#{border}#{l.ljust length}#{border}" }.join "\n"
+ end
end
# many instances of this class create a stack-like structure
class TextStructure
# the text of the instance
attr_accessor :text
# instance of TextStructure (the stack-like structure)
attr_accessor :subtext
# each instance has a parent, except the first one
attr_accessor :parent
+ # whether to put a new line after each text adding in the subtext
+ attr_accessor :vertical
- def initialize(parent = nil)
+ def initialize(parent = nil, vertical = false)
@parent = parent
+ @subtext = nil
+ @text = ""
+ @vertical = vertical
end
def add_text(text)
@text += text
+ @text += "\n" if @vertical
+ @text
end
# creates a subtext and returns it so it can be assigned to @result
# the global @result in TextScreen must be evaluated
# after adding text is finished to return to this node
- def create_subtext
- @subtext = TextStructure.new self
+ def create_subtext(vertical = false)
+ @subtext = TextStructure.new self, vertical
end
# this is not needed actually, but it's here, get used to it (:
def evaluate_subtext
@text += @subtext.text
@subtext = nil
end
# adds this text to the parent's text
# clears the subtext of the parent
# and returns the parent so it can be assigned to @result
def evaluate_self
- if not @parent then @text end
+ if not @parent then return @text end
@parent.text += @text
+ @parent.text += "\n" if @parent.vertical
@parent.subtext = nil
@parent
end
end
# a stack-like structure for storing the styles
# reading the top element "stack" is handled in a special way
class StyleManager
def self.initialize
@styles_stack = []
end
def self.push(style)
@styles_stack = [] if not defined? @styles_stack
@styles_stack.push style
end
def self.apply_style(text)
if not defined? @styles_stack then @styles_stack = [] end
# drop through all nils
- style = @styles_stack.reverse.first { |i| ! i }
+ style = @styles_stack.reverse.to_enum.find { |i| i }
# apply the style and return
case style
when :upcase then text.upcase
when :downcase then text.downcase
else text
end
end
def self.pop
@styles_stack = [] if not defined? @styles_stack
@styles_stack.pop
end
end
end