Йоана обнови решението на 23.11.2014 21:42 (преди около 10 години)
+module UI
+ class TextScreen
+ def self.draw(&block)
+ group = Group.new
+ group.instance_exec(&block)
+ group.render
+ end
+ end
+
+ class Group
+ def initialize(border = nil, group_style = nil, &block)
+ @labels = []
+ define_singleton_method :horizontal,
+ horizontal_implementation(group_style)
+ define_singleton_method :vertical, vertical_implementation(group_style)
+ end
+
+ def label(**args)
+ horizontal { label(args) }
+ end
+
+ def render
+ @labels.join ''
+ end
+
+ protected
+
+ def horizontal_implementation(group_style)
+ -> (border: nil, style: group_style, &block) do
+ @labels << HorizontalGroup.new(border, style, &block).render
+ end
+ end
+
+ def vertical_implementation(group_style)
+ -> (border: nil, style: group_style, &block) do
+ @labels << VerticalGroup.new(border, style, &block).render
+ end
+ end
+ end
+
+ class HorizontalGroup < Group
+ def initialize(border = nil, group_style = nil, &block)
+ super
+ define_singleton_method :render, render_implementation(border)
+ define_singleton_method :label, Label.label_implementation(group_style)
+ instance_exec(&block)
+ end
+
+ protected
+
+ def render_implementation(border)
+ -> { "#{border}#{@labels.join ''}#{border}" }
+ end
+ end
+
+ class VerticalGroup < Group
+ def initialize(border = nil, group_style = nil, &block)
+ super
+ define_singleton_method :render do
+ render_implementation(border)
+ end
+ define_singleton_method :label, Label.label_implementation(group_style)
+ instance_exec(&block)
+ end
+
+ protected
+
+ def render_implementation(border)
+ width = @labels.max_by(&:length).length
+ @labels.flat_map { |label| [border, label.ljust(width), border, "\n"] }
+ .join ''
+ end
+ end
+
+ module Label
+ def self.label_implementation(group_style)
+ -> (text:, border: nil, style: group_style) do
+ @labels << Label.render(text, border, style)
+ end
+ end
+
+ def self.render(text, border, style)
+ "#{border}#{style ? style.to_proc.call(text) : text}#{border}"
+ end
+ end
+end