whirled_peas 0.4.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +37 -0
- data/README.md +529 -156
- data/Rakefile +9 -3
- data/bin/reset_cursor +11 -0
- data/bin/screen_test +68 -0
- data/examples/intro.rb +52 -0
- data/examples/scrolling.rb +54 -0
- data/lib/whirled_peas.rb +6 -12
- data/lib/whirled_peas/animator.rb +5 -0
- data/lib/whirled_peas/animator/debug_consumer.rb +17 -0
- data/lib/whirled_peas/animator/easing.rb +72 -0
- data/lib/whirled_peas/animator/frame.rb +5 -0
- data/lib/whirled_peas/animator/frameset.rb +33 -0
- data/lib/whirled_peas/animator/producer.rb +35 -0
- data/lib/whirled_peas/animator/renderer_consumer.rb +31 -0
- data/lib/whirled_peas/command.rb +5 -0
- data/lib/whirled_peas/command/base.rb +86 -0
- data/lib/whirled_peas/command/config_command.rb +44 -0
- data/lib/whirled_peas/command/debug.rb +21 -0
- data/lib/whirled_peas/command/fonts.rb +22 -0
- data/lib/whirled_peas/command/frame_command.rb +34 -0
- data/lib/whirled_peas/command/frames.rb +24 -0
- data/lib/whirled_peas/command/help.rb +38 -0
- data/lib/whirled_peas/command/play.rb +108 -0
- data/lib/whirled_peas/command/record.rb +57 -0
- data/lib/whirled_peas/command/still.rb +29 -0
- data/lib/whirled_peas/command_line.rb +23 -228
- data/lib/whirled_peas/config.rb +56 -6
- data/lib/whirled_peas/device.rb +5 -0
- data/lib/whirled_peas/device/null_device.rb +8 -0
- data/lib/whirled_peas/device/output_file.rb +19 -0
- data/lib/whirled_peas/device/screen.rb +26 -0
- data/lib/whirled_peas/errors.rb +2 -0
- data/lib/whirled_peas/graphics.rb +19 -0
- data/lib/whirled_peas/graphics/box_painter.rb +101 -0
- data/lib/whirled_peas/graphics/canvas.rb +118 -0
- data/lib/whirled_peas/graphics/composer.rb +80 -0
- data/lib/whirled_peas/graphics/container_coords.rb +72 -0
- data/lib/whirled_peas/graphics/container_dimensions.rb +93 -0
- data/lib/whirled_peas/graphics/container_painter.rb +363 -0
- data/lib/whirled_peas/graphics/debugger.rb +52 -0
- data/lib/whirled_peas/graphics/grid_painter.rb +69 -0
- data/lib/whirled_peas/graphics/mock_screen.rb +26 -0
- data/lib/whirled_peas/graphics/painter.rb +33 -0
- data/lib/whirled_peas/graphics/renderer.rb +32 -0
- data/lib/whirled_peas/graphics/text_dimensions.rb +15 -0
- data/lib/whirled_peas/graphics/text_painter.rb +40 -0
- data/lib/whirled_peas/settings.rb +5 -0
- data/lib/whirled_peas/settings/alignment.rb +24 -0
- data/lib/whirled_peas/settings/bg_color.rb +24 -0
- data/lib/whirled_peas/settings/border.rb +101 -0
- data/lib/whirled_peas/settings/box_settings.rb +8 -0
- data/lib/whirled_peas/settings/color.rb +68 -0
- data/lib/whirled_peas/settings/container_settings.rb +223 -0
- data/lib/whirled_peas/settings/debugger.rb +96 -0
- data/lib/whirled_peas/settings/display_flow.rb +27 -0
- data/lib/whirled_peas/settings/element_settings.rb +61 -0
- data/lib/whirled_peas/settings/grid_settings.rb +19 -0
- data/lib/whirled_peas/settings/margin.rb +8 -0
- data/lib/whirled_peas/settings/padding.rb +8 -0
- data/lib/whirled_peas/settings/position.rb +15 -0
- data/lib/whirled_peas/settings/scrollbar.rb +15 -0
- data/lib/whirled_peas/settings/sizing.rb +19 -0
- data/lib/whirled_peas/settings/spacing.rb +58 -0
- data/lib/whirled_peas/settings/text_color.rb +21 -0
- data/lib/whirled_peas/settings/text_settings.rb +15 -0
- data/lib/whirled_peas/settings/vert_alignment.rb +24 -0
- data/lib/whirled_peas/utils/ansi.rb +19 -56
- data/lib/whirled_peas/utils/file_handler.rb +57 -0
- data/lib/whirled_peas/utils/formatted_string.rb +64 -0
- data/lib/whirled_peas/utils/title_font.rb +1 -1
- data/lib/whirled_peas/version.rb +1 -1
- data/screen_test/elements/box.frame +1 -0
- data/screen_test/elements/box.rb +20 -0
- data/screen_test/elements/grid.frame +1 -0
- data/screen_test/elements/grid.rb +13 -0
- data/screen_test/elements/screen_overflow_x.frame +1 -0
- data/screen_test/elements/screen_overflow_x.rb +9 -0
- data/screen_test/elements/screen_overflow_y.frame +1 -0
- data/screen_test/elements/screen_overflow_y.rb +9 -0
- data/screen_test/elements/text.frame +1 -0
- data/screen_test/elements/text.rb +9 -0
- data/screen_test/elements/text_multiline.frame +1 -0
- data/screen_test/elements/text_multiline.rb +9 -0
- data/screen_test/settings/align/box_around.frame +1 -0
- data/screen_test/settings/align/box_around.rb +16 -0
- data/screen_test/settings/align/box_between.frame +1 -0
- data/screen_test/settings/align/box_between.rb +16 -0
- data/screen_test/settings/align/box_center.frame +1 -0
- data/screen_test/settings/align/box_center.rb +21 -0
- data/screen_test/settings/align/box_default.frame +1 -0
- data/screen_test/settings/align/box_default.rb +20 -0
- data/screen_test/settings/align/box_evenly.frame +1 -0
- data/screen_test/settings/align/box_evenly.rb +16 -0
- data/screen_test/settings/align/box_left.frame +1 -0
- data/screen_test/settings/align/box_left.rb +21 -0
- data/screen_test/settings/align/box_right.frame +1 -0
- data/screen_test/settings/align/box_right.rb +21 -0
- data/screen_test/settings/align/children_center.frame +1 -0
- data/screen_test/settings/align/children_center.rb +15 -0
- data/screen_test/settings/align/children_left.frame +1 -0
- data/screen_test/settings/align/children_left.rb +15 -0
- data/screen_test/settings/align/children_right.frame +1 -0
- data/screen_test/settings/align/children_right.rb +15 -0
- data/screen_test/settings/align/grid_center.frame +1 -0
- data/screen_test/settings/align/grid_center.rb +18 -0
- data/screen_test/settings/align/grid_default.frame +1 -0
- data/screen_test/settings/align/grid_default.rb +17 -0
- data/screen_test/settings/align/grid_left.frame +1 -0
- data/screen_test/settings/align/grid_left.rb +18 -0
- data/screen_test/settings/align/grid_right.frame +1 -0
- data/screen_test/settings/align/grid_right.rb +18 -0
- data/screen_test/settings/ansi/bold.frame +1 -0
- data/screen_test/settings/ansi/bold.rb +14 -0
- data/screen_test/settings/ansi/color.frame +1 -0
- data/screen_test/settings/ansi/color.rb +37 -0
- data/screen_test/settings/ansi/underline.frame +1 -0
- data/screen_test/settings/ansi/underline.rb +14 -0
- data/screen_test/settings/border.frame +1 -0
- data/screen_test/settings/border.rb +13 -0
- data/screen_test/settings/flow/box_b2t.frame +1 -0
- data/screen_test/settings/flow/box_b2t.rb +26 -0
- data/screen_test/settings/flow/box_l2r.frame +1 -0
- data/screen_test/settings/flow/box_l2r.rb +26 -0
- data/screen_test/settings/flow/box_r2l.frame +1 -0
- data/screen_test/settings/flow/box_r2l.rb +26 -0
- data/screen_test/settings/flow/box_t2b.frame +1 -0
- data/screen_test/settings/flow/box_t2b.rb +26 -0
- data/screen_test/settings/flow/grid_b2t.frame +1 -0
- data/screen_test/settings/flow/grid_b2t.rb +14 -0
- data/screen_test/settings/flow/grid_l2r.frame +1 -0
- data/screen_test/settings/flow/grid_l2r.rb +14 -0
- data/screen_test/settings/flow/grid_r2l.frame +1 -0
- data/screen_test/settings/flow/grid_r2l.rb +14 -0
- data/screen_test/settings/flow/grid_t2b.frame +1 -0
- data/screen_test/settings/flow/grid_t2b.rb +14 -0
- data/screen_test/settings/height/box.frame +1 -0
- data/screen_test/settings/height/box.rb +13 -0
- data/screen_test/settings/height/box_border_sizing.frame +1 -0
- data/screen_test/settings/height/box_border_sizing.rb +15 -0
- data/screen_test/settings/height/grid.frame +1 -0
- data/screen_test/settings/height/grid.rb +14 -0
- data/screen_test/settings/height/overflow_box.frame +1 -0
- data/screen_test/settings/height/overflow_box.rb +13 -0
- data/screen_test/settings/height/overflow_box_l2r.frame +1 -0
- data/screen_test/settings/height/overflow_box_l2r.rb +17 -0
- data/screen_test/settings/height/overflow_box_t2b.frame +1 -0
- data/screen_test/settings/height/overflow_box_t2b.rb +16 -0
- data/screen_test/settings/height/overflow_grid.frame +1 -0
- data/screen_test/settings/height/overflow_grid.rb +16 -0
- data/screen_test/settings/margin.frame +1 -0
- data/screen_test/settings/margin.rb +16 -0
- data/screen_test/settings/padding.frame +1 -0
- data/screen_test/settings/padding.rb +13 -0
- data/screen_test/settings/position/box_left.frame +1 -0
- data/screen_test/settings/position/box_left.rb +17 -0
- data/screen_test/settings/position/box_left_negative.frame +1 -0
- data/screen_test/settings/position/box_left_negative.rb +17 -0
- data/screen_test/settings/position/box_top.frame +1 -0
- data/screen_test/settings/position/box_top.rb +17 -0
- data/screen_test/settings/position/box_top_negative.frame +1 -0
- data/screen_test/settings/position/box_top_negative.rb +17 -0
- data/screen_test/settings/position/grid_left.frame +1 -0
- data/screen_test/settings/position/grid_left.rb +18 -0
- data/screen_test/settings/position/grid_left_negative.frame +1 -0
- data/screen_test/settings/position/grid_left_negative.rb +18 -0
- data/screen_test/settings/position/grid_top.frame +1 -0
- data/screen_test/settings/position/grid_top.rb +18 -0
- data/screen_test/settings/position/grid_top_negative.frame +1 -0
- data/screen_test/settings/position/grid_top_negative.rb +18 -0
- data/screen_test/settings/scroll/horiz_box.frame +1 -0
- data/screen_test/settings/scroll/horiz_box.rb +17 -0
- data/screen_test/settings/scroll/horiz_box_align_center.rb +18 -0
- data/screen_test/settings/scroll/horiz_box_align_right.rb +18 -0
- data/screen_test/settings/scroll/vert_box.frame +1 -0
- data/screen_test/settings/scroll/vert_box.rb +20 -0
- data/screen_test/settings/title_font.frame +1 -0
- data/screen_test/settings/title_font.rb +12 -0
- data/screen_test/settings/valign/box_around.frame +1 -0
- data/screen_test/settings/valign/box_around.rb +17 -0
- data/screen_test/settings/valign/box_between.frame +1 -0
- data/screen_test/settings/valign/box_between.rb +17 -0
- data/screen_test/settings/valign/box_bottom.frame +1 -0
- data/screen_test/settings/valign/box_bottom.rb +17 -0
- data/screen_test/settings/valign/box_default.frame +1 -0
- data/screen_test/settings/valign/box_default.rb +16 -0
- data/screen_test/settings/valign/box_evenly.frame +1 -0
- data/screen_test/settings/valign/box_evenly.rb +17 -0
- data/screen_test/settings/valign/box_middle.frame +1 -0
- data/screen_test/settings/valign/box_middle.rb +17 -0
- data/screen_test/settings/valign/box_top.frame +1 -0
- data/screen_test/settings/valign/box_top.rb +17 -0
- data/screen_test/settings/valign/grid_bottom.frame +1 -0
- data/screen_test/settings/valign/grid_bottom.rb +15 -0
- data/screen_test/settings/valign/grid_default.frame +1 -0
- data/screen_test/settings/valign/grid_default.rb +14 -0
- data/screen_test/settings/valign/grid_middle.frame +1 -0
- data/screen_test/settings/valign/grid_middle.rb +15 -0
- data/screen_test/settings/valign/grid_top.frame +1 -0
- data/screen_test/settings/valign/grid_top.rb +15 -0
- data/screen_test/settings/width/box_border_sizing.frame +1 -0
- data/screen_test/settings/width/box_border_sizing.rb +15 -0
- data/screen_test/settings/width/box_content.frame +1 -0
- data/screen_test/settings/width/box_content.rb +15 -0
- data/screen_test/settings/width/box_default.frame +1 -0
- data/screen_test/settings/width/box_default.rb +14 -0
- data/screen_test/settings/width/grid.frame +1 -0
- data/screen_test/settings/width/grid.rb +14 -0
- data/screen_test/settings/width/overflow_align_center.frame +1 -0
- data/screen_test/settings/width/overflow_align_center.rb +14 -0
- data/screen_test/settings/width/overflow_align_right.frame +1 -0
- data/screen_test/settings/width/overflow_align_right.rb +14 -0
- data/screen_test/settings/width/overflow_box.frame +1 -0
- data/screen_test/settings/width/overflow_box.rb +13 -0
- data/screen_test/settings/width/overflow_box_l2r.frame +1 -0
- data/screen_test/settings/width/overflow_box_l2r.rb +16 -0
- data/screen_test/settings/width/overflow_box_t2b.frame +1 -0
- data/screen_test/settings/width/overflow_box_t2b.rb +17 -0
- data/screen_test/settings/width/overflow_grid.frame +1 -0
- data/screen_test/settings/width/overflow_grid.rb +14 -0
- data/tools/whirled_peas/tools/screen_tester.rb +285 -0
- metadata +213 -15
- data/bin/title_fonts +0 -6
- data/lib/whirled_peas/frame.rb +0 -7
- data/lib/whirled_peas/frame/event_loop.rb +0 -91
- data/lib/whirled_peas/frame/print_consumer.rb +0 -33
- data/lib/whirled_peas/frame/producer.rb +0 -61
- data/lib/whirled_peas/template.rb +0 -5
- data/lib/whirled_peas/template/element.rb +0 -230
- data/lib/whirled_peas/template/settings.rb +0 -530
- data/lib/whirled_peas/ui.rb +0 -5
- data/lib/whirled_peas/ui/canvas.rb +0 -68
- data/lib/whirled_peas/ui/painter.rb +0 -287
- data/lib/whirled_peas/ui/screen.rb +0 -63
- data/lib/whirled_peas/utils/color.rb +0 -101
| @@ -1,232 +1,21 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                    msg = %Q(#{msg.class}: #{msg.to_s}\n    #{msg.backtrace.join("\n    ")})
         | 
| 9 | 
            -
                  end
         | 
| 10 | 
            -
                  "[#{severity}] #{datetime.strftime('%Y-%m-%dT%H:%M:%S.%L')} (#{progname}) - #{msg}\n"
         | 
| 11 | 
            -
                end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                def self.command_name
         | 
| 14 | 
            -
                  self.name.split('::').last.sub(/Command$/, '').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                def self.build_logger(output, level=DEFAULT_LOG_LEVEL, formatter=DEFAULT_FORMATTER)
         | 
| 18 | 
            -
                  logger = Logger.new(output)
         | 
| 19 | 
            -
                  logger.level = level
         | 
| 20 | 
            -
                  logger.formatter = formatter
         | 
| 21 | 
            -
                  logger
         | 
| 22 | 
            -
                end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                attr_reader :args
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                def initialize(args)
         | 
| 27 | 
            -
                  @args = args
         | 
| 28 | 
            -
                end
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                def valid?
         | 
| 31 | 
            -
                  @error_text = nil
         | 
| 32 | 
            -
                  validate!
         | 
| 33 | 
            -
                  @error_text.nil?
         | 
| 34 | 
            -
                end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                def print_error
         | 
| 37 | 
            -
                  puts @error_text if @error_text
         | 
| 38 | 
            -
                  print_usage
         | 
| 39 | 
            -
                end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                def start
         | 
| 42 | 
            -
                end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                private
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                def print_usage
         | 
| 47 | 
            -
                  puts "Usage: #{$0} #{self.class.command_name}"
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                def validate!
         | 
| 51 | 
            -
                  # Set @error_text if the options are not valid
         | 
| 52 | 
            -
                end
         | 
| 53 | 
            -
              end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
              class TitleFontsCommand < Command
         | 
| 56 | 
            -
                def start
         | 
| 57 | 
            -
                  require 'whirled_peas/utils/title_font'
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                  Utils::TitleFont.fonts.keys.each do |key|
         | 
| 60 | 
            -
                    puts Utils::TitleFont.to_s(key.to_s, key)
         | 
| 61 | 
            -
                    puts key.inspect
         | 
| 62 | 
            -
                    puts
         | 
| 63 | 
            -
                  end
         | 
| 64 | 
            -
                end
         | 
| 65 | 
            -
              end
         | 
| 66 | 
            -
             | 
| 67 | 
            -
              class ConfigCommand < Command
         | 
| 68 | 
            -
                def start
         | 
| 69 | 
            -
                  require config
         | 
| 70 | 
            -
                end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                private
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                attr_reader :config
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                def validate!
         | 
| 77 | 
            -
                  if args.length == 0
         | 
| 78 | 
            -
                    @error_text = "#{self.class.command_name} requires a config file"
         | 
| 79 | 
            -
                  elsif !File.exist?(args[0])
         | 
| 80 | 
            -
                    @error_text = "File not found: #{args[0]}"
         | 
| 81 | 
            -
                  elsif args[0][-3..-1] != '.rb'
         | 
| 82 | 
            -
                    @error_text = 'Config file should be a .rb file'
         | 
| 83 | 
            -
                  else
         | 
| 84 | 
            -
                    @config = args[0][0] == '/' ? args[0] : File.join(Dir.pwd, args[0])
         | 
| 85 | 
            -
                  end
         | 
| 86 | 
            -
                end
         | 
| 87 | 
            -
             | 
| 88 | 
            -
                def print_usage
         | 
| 89 | 
            -
                  puts "Usage: #{$0} #{self.class.command_name} <config file>"
         | 
| 90 | 
            -
                end
         | 
| 91 | 
            -
              end
         | 
| 92 | 
            -
             | 
| 93 | 
            -
              class StartCommand < ConfigCommand
         | 
| 94 | 
            -
                LOGGER_ID = 'MAIN'
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                def start
         | 
| 97 | 
            -
                  super
         | 
| 98 | 
            -
                  require 'whirled_peas/frame/event_loop'
         | 
| 99 | 
            -
                  require 'whirled_peas/frame/producer'
         | 
| 100 | 
            -
             | 
| 101 | 
            -
                  logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
         | 
| 102 | 
            -
             | 
| 103 | 
            -
                  consumer = Frame::EventLoop.new(
         | 
| 104 | 
            -
                    WhirledPeas.config.template_factory,
         | 
| 105 | 
            -
                    WhirledPeas.config.loading_template_factory,
         | 
| 106 | 
            -
                    DEFAULT_REFRESH_RATE,
         | 
| 107 | 
            -
                    logger
         | 
| 108 | 
            -
                  )
         | 
| 109 | 
            -
                  Frame::Producer.produce(consumer, logger) do |producer|
         | 
| 110 | 
            -
                    begin
         | 
| 111 | 
            -
                      WhirledPeas.config.driver.start(producer)
         | 
| 112 | 
            -
                    rescue => e
         | 
| 113 | 
            -
                      logger.warn(LOGGER_ID) { 'Driver exited with error, terminating producer...' }
         | 
| 114 | 
            -
                      logger.error(LOGGER_ID) { e }
         | 
| 115 | 
            -
                      raise
         | 
| 116 | 
            -
                    end
         | 
| 117 | 
            -
                  end
         | 
| 118 | 
            -
                end
         | 
| 119 | 
            -
              end
         | 
| 120 | 
            -
             | 
| 121 | 
            -
              class ListFramesCommand < ConfigCommand
         | 
| 122 | 
            -
                def start
         | 
| 123 | 
            -
                  super
         | 
| 124 | 
            -
                  require 'whirled_peas/frame/print_consumer'
         | 
| 125 | 
            -
                  require 'whirled_peas/frame/producer'
         | 
| 126 | 
            -
             | 
| 127 | 
            -
                  logger = self.class.build_logger(STDOUT)
         | 
| 128 | 
            -
                  Frame::Producer.produce(Frame::PrintConsumer.new, logger) do |producer|
         | 
| 129 | 
            -
                    begin
         | 
| 130 | 
            -
                      WhirledPeas.config.driver.start(producer)
         | 
| 131 | 
            -
                    rescue => e
         | 
| 132 | 
            -
                      logger.warn(LOGGER_ID) { 'Driver exited with error, terminating producer...' }
         | 
| 133 | 
            -
                      logger.error(LOGGER_ID) { e }
         | 
| 134 | 
            -
                      raise
         | 
| 135 | 
            -
                    end
         | 
| 136 | 
            -
                  end
         | 
| 137 | 
            -
                end
         | 
| 138 | 
            -
              end
         | 
| 139 | 
            -
             | 
| 140 | 
            -
              class PlayFrameCommand < ConfigCommand
         | 
| 141 | 
            -
                def start
         | 
| 142 | 
            -
                  super
         | 
| 143 | 
            -
             | 
| 144 | 
            -
                  if args.last == '--debug'
         | 
| 145 | 
            -
                    puts WhirledPeas.config.template_factory.build(frame, frame_args).inspect
         | 
| 146 | 
            -
                    exit
         | 
| 147 | 
            -
                  end
         | 
| 148 | 
            -
             | 
| 149 | 
            -
                  require 'whirled_peas/frame/event_loop'
         | 
| 150 | 
            -
                  require 'whirled_peas/frame/producer'
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                  logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
         | 
| 153 | 
            -
             | 
| 154 | 
            -
                  consumer = Frame::EventLoop.new(
         | 
| 155 | 
            -
                    WhirledPeas.config.template_factory,
         | 
| 156 | 
            -
                    WhirledPeas.config.loading_template_factory,
         | 
| 157 | 
            -
                    DEFAULT_REFRESH_RATE,
         | 
| 158 | 
            -
                    logger
         | 
| 159 | 
            -
                  )
         | 
| 160 | 
            -
                  Frame::Producer.produce(consumer, logger) do |producer|
         | 
| 161 | 
            -
                    producer.send_frame(args[1], duration: 5, args: frame_args)
         | 
| 162 | 
            -
                  end
         | 
| 163 | 
            -
                end
         | 
| 164 | 
            -
             | 
| 165 | 
            -
                private
         | 
| 166 | 
            -
             | 
| 167 | 
            -
                attr_reader :frame, :frame_args
         | 
| 168 | 
            -
             | 
| 169 | 
            -
                def validate!
         | 
| 170 | 
            -
                  super
         | 
| 171 | 
            -
                  if !@error_text.nil?
         | 
| 172 | 
            -
                    return
         | 
| 173 | 
            -
                  elsif args.length < 2
         | 
| 174 | 
            -
                    @error_text = "#{self.class.command_name} requires a frame name"
         | 
| 175 | 
            -
                  else
         | 
| 176 | 
            -
                    require 'json'
         | 
| 177 | 
            -
                    @frame = args[1]
         | 
| 178 | 
            -
                    @frame_args = {}
         | 
| 179 | 
            -
                    JSON.parse(args[2] || '{}').each do |key, value|
         | 
| 180 | 
            -
                      @frame_args[key.to_sym] = value
         | 
| 181 | 
            -
                    end
         | 
| 182 | 
            -
                  end
         | 
| 183 | 
            -
                end
         | 
| 184 | 
            -
             | 
| 185 | 
            -
                def print_usage
         | 
| 186 | 
            -
                  puts "Usage: #{$0} #{self.class.command_name} <config file> <frame> [args as a JSON string] [--debug]"
         | 
| 187 | 
            -
                end
         | 
| 188 | 
            -
              end
         | 
| 189 | 
            -
             | 
| 190 | 
            -
              class LoadingCommand < ConfigCommand
         | 
| 191 | 
            -
                def start
         | 
| 192 | 
            -
                  super
         | 
| 193 | 
            -
                  unless WhirledPeas.config.loading_template_factory
         | 
| 194 | 
            -
                    puts 'No loading screen configured'
         | 
| 195 | 
            -
                    exit
         | 
| 196 | 
            -
                  end
         | 
| 197 | 
            -
             | 
| 198 | 
            -
                  if args.last == '--debug'
         | 
| 199 | 
            -
                    puts WhirledPeas.config.loading_template_factory.build.inspect
         | 
| 200 | 
            -
                    exit
         | 
| 201 | 
            -
                  end
         | 
| 202 | 
            -
             | 
| 203 | 
            -
                  require 'whirled_peas/frame/event_loop'
         | 
| 204 | 
            -
                  require 'whirled_peas/frame/producer'
         | 
| 205 | 
            -
             | 
| 206 | 
            -
                  logger = self.class.build_logger(File.open('whirled_peas.log', 'a'))
         | 
| 207 | 
            -
                  consumer = Frame::EventLoop.new(
         | 
| 208 | 
            -
                    WhirledPeas.config.template_factory,
         | 
| 209 | 
            -
                    WhirledPeas.config.loading_template_factory,
         | 
| 210 | 
            -
                    DEFAULT_REFRESH_RATE,
         | 
| 211 | 
            -
                    logger
         | 
| 212 | 
            -
                  )
         | 
| 213 | 
            -
                  Frame::Producer.produce(consumer, logger) { sleep(5) }
         | 
| 214 | 
            -
                end
         | 
| 215 | 
            -
             | 
| 216 | 
            -
                private
         | 
| 217 | 
            -
             | 
| 218 | 
            -
                def print_usage
         | 
| 219 | 
            -
                  puts "Usage: #{$0} #{self.class.command_name} [--debug]"
         | 
| 220 | 
            -
                end
         | 
| 221 | 
            -
              end
         | 
| 1 | 
            +
            require 'whirled_peas/command/debug'
         | 
| 2 | 
            +
            require 'whirled_peas/command/fonts'
         | 
| 3 | 
            +
            require 'whirled_peas/command/frames'
         | 
| 4 | 
            +
            require 'whirled_peas/command/help'
         | 
| 5 | 
            +
            require 'whirled_peas/command/play'
         | 
| 6 | 
            +
            require 'whirled_peas/command/record'
         | 
| 7 | 
            +
            require 'whirled_peas/command/still'
         | 
| 222 8 |  | 
| 9 | 
            +
            module WhirledPeas
         | 
| 223 10 | 
             
              class CommandLine
         | 
| 224 11 | 
             
                COMMANDS = [
         | 
| 225 | 
            -
                   | 
| 226 | 
            -
                   | 
| 227 | 
            -
                   | 
| 228 | 
            -
                   | 
| 229 | 
            -
                   | 
| 12 | 
            +
                  Command::Debug,
         | 
| 13 | 
            +
                  Command::Fonts,
         | 
| 14 | 
            +
                  Command::Frames,
         | 
| 15 | 
            +
                  Command::Help,
         | 
| 16 | 
            +
                  Command::Play,
         | 
| 17 | 
            +
                  Command::Record,
         | 
| 18 | 
            +
                  Command::Still
         | 
| 230 19 | 
             
                ].map.with_object({}) { |c, h| h[c.command_name] = c }
         | 
| 231 20 |  | 
| 232 21 | 
             
                def initialize(args)
         | 
| @@ -247,7 +36,7 @@ module WhirledPeas | |
| 247 36 | 
             
                    exit(1)
         | 
| 248 37 | 
             
                  end
         | 
| 249 38 |  | 
| 250 | 
            -
                  cmd = COMMANDS[command].new(args)
         | 
| 39 | 
            +
                  cmd = COMMANDS[command].new(args, WhirledPeas.config)
         | 
| 251 40 |  | 
| 252 41 | 
             
                  unless cmd.valid?
         | 
| 253 42 | 
             
                    cmd.print_error
         | 
| @@ -264,7 +53,13 @@ module WhirledPeas | |
| 264 53 | 
             
                def print_usage
         | 
| 265 54 | 
             
                  puts "Usage: #{$0} <command> [command options]"
         | 
| 266 55 | 
             
                  puts
         | 
| 267 | 
            -
                  puts  | 
| 56 | 
            +
                  puts 'Available commands:'
         | 
| 57 | 
            +
                  puts
         | 
| 58 | 
            +
                  max_name_length = 0
         | 
| 59 | 
            +
                  COMMANDS.keys.each { |c| max_name_length = c.length if c.length > max_name_length }
         | 
| 60 | 
            +
                  COMMANDS.each do |name, klass|
         | 
| 61 | 
            +
                    puts "    #{name.ljust(max_name_length, ' ')}    #{klass.description}"
         | 
| 62 | 
            +
                  end
         | 
| 268 63 | 
             
                end
         | 
| 269 64 | 
             
              end
         | 
| 270 65 | 
             
            end
         | 
    
        data/lib/whirled_peas/config.rb
    CHANGED
    
    | @@ -1,13 +1,47 @@ | |
| 1 | 
            +
            require 'logger'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module WhirledPeas
         | 
| 2 4 | 
             
              class Config
         | 
| 3 | 
            -
                 | 
| 4 | 
            -
                 | 
| 5 | 
            +
                # Refreshed rate measured in frames per second
         | 
| 6 | 
            +
                DEFAULT_REFRESH_RATE = 30
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                DEFAULT_LOG_LEVEL = Logger::INFO
         | 
| 9 | 
            +
                DEFAULT_LOG_FILE = 'whirled_peas.log'
         | 
| 5 10 |  | 
| 6 | 
            -
                 | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 11 | 
            +
                # This formatter expects a loggers to send `progname` in each log call. This value
         | 
| 12 | 
            +
                # should be an all uppercase version of the module or class that is invoking the
         | 
| 13 | 
            +
                # logger. Ruby's logger supports setting this value on a per-log statement basis
         | 
| 14 | 
            +
                # when the log message is passed in through a block:
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                #   logger.<level>(progname, &block)
         | 
| 17 | 
            +
                #
         | 
| 18 | 
            +
                # E.g.
         | 
| 19 | 
            +
                #
         | 
| 20 | 
            +
                #   class Foo
         | 
| 21 | 
            +
                #     def bar
         | 
| 22 | 
            +
                #       logger.warn('FOO') { 'Something fishy happened in #bar' }
         | 
| 23 | 
            +
                #     end
         | 
| 24 | 
            +
                #   end
         | 
| 25 | 
            +
                #
         | 
| 26 | 
            +
                # The block format also has the advantage that the evaluation of the block only
         | 
| 27 | 
            +
                # occurs if the message gets logged. So expensive to calculate debug statements
         | 
| 28 | 
            +
                # will not impact the performance of the application if the log level is INFO or
         | 
| 29 | 
            +
                # higher.
         | 
| 30 | 
            +
                DEFAULT_FORMATTER = proc do |severity, datetime, progname, msg|
         | 
| 31 | 
            +
                  # Convert an instance of an exception into a nicely formatted message string
         | 
| 32 | 
            +
                  if msg.is_a?(Exception)
         | 
| 33 | 
            +
                    msg = %Q(#{msg.class}: #{msg.to_s}\n    #{msg.backtrace.join("\n    ")})
         | 
| 9 34 | 
             
                  end
         | 
| 10 | 
            -
                   | 
| 35 | 
            +
                  "[#{severity}] #{datetime.strftime('%Y-%m-%dT%H:%M:%S.%L')} (#{progname}) - #{msg}\n"
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                attr_writer :application, :template_factory, :refresh_rate, :log_level, :log_formatter, :log_file
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def application
         | 
| 41 | 
            +
                  unless @application
         | 
| 42 | 
            +
                    raise ConfigurationError, 'application must be configured'
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                  @application
         | 
| 11 45 | 
             
                end
         | 
| 12 46 |  | 
| 13 47 | 
             
                def template_factory
         | 
| @@ -16,6 +50,22 @@ module WhirledPeas | |
| 16 50 | 
             
                  end
         | 
| 17 51 | 
             
                  @template_factory
         | 
| 18 52 | 
             
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def refresh_rate
         | 
| 55 | 
            +
                  @refresh_rate || DEFAULT_REFRESH_RATE
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def log_level
         | 
| 59 | 
            +
                  @log_level || DEFAULT_LOG_LEVEL
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def log_formatter
         | 
| 63 | 
            +
                  @log_formatter || DEFAULT_FORMATTER
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def log_file
         | 
| 67 | 
            +
                  @log_file || DEFAULT_LOG_FILE
         | 
| 68 | 
            +
                end
         | 
| 19 69 | 
             
              end
         | 
| 20 70 | 
             
              private_constant :Config
         | 
| 21 71 | 
             
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            require 'whirled_peas/utils/file_handler'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module WhirledPeas
         | 
| 4 | 
            +
              module Device
         | 
| 5 | 
            +
                class OutputFile
         | 
| 6 | 
            +
                  def initialize(file)
         | 
| 7 | 
            +
                    @file = file
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def handle_renders(renders)
         | 
| 11 | 
            +
                    Utils::FileHandler.write(file, renders)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  private
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  attr_reader :file
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require 'highline'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module WhirledPeas
         | 
| 4 | 
            +
              module Device
         | 
| 5 | 
            +
                class Screen
         | 
| 6 | 
            +
                  def initialize(refresh_rate, output: STDOUT)
         | 
| 7 | 
            +
                    @refresh_rate = refresh_rate
         | 
| 8 | 
            +
                    @output = output
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def handle_renders(renders)
         | 
| 12 | 
            +
                    renders.each do |strokes|
         | 
| 13 | 
            +
                      frame_at = Time.now
         | 
| 14 | 
            +
                      output.print(strokes)
         | 
| 15 | 
            +
                      output.flush
         | 
| 16 | 
            +
                      next_frame_at = frame_at + 1.0 / refresh_rate
         | 
| 17 | 
            +
                      sleep([0, next_frame_at - Time.now].max)
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  private
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  attr_reader :refresh_rate, :output
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
    
        data/lib/whirled_peas/errors.rb
    CHANGED
    
    
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module WhirledPeas
         | 
| 2 | 
            +
              module Graphics
         | 
| 3 | 
            +
                class << self
         | 
| 4 | 
            +
                  attr_accessor :debug
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def debugger(string_or_proc)
         | 
| 7 | 
            +
                    return unless @debug
         | 
| 8 | 
            +
                    @debugger ||= Logger.new(STDOUT, level: Logger::DEBUG)
         | 
| 9 | 
            +
                    if string_or_proc.is_a?(Proc)
         | 
| 10 | 
            +
                      string = string_or_proc.call
         | 
| 11 | 
            +
                    else
         | 
| 12 | 
            +
                      string = string_or_proc
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                    @debugger.debug(string)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              private_constant :Graphics
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,101 @@ | |
| 1 | 
            +
            require_relative 'container_painter'
         | 
| 2 | 
            +
            require_relative 'container_dimensions'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module WhirledPeas
         | 
| 5 | 
            +
              module Graphics
         | 
| 6 | 
            +
                class BoxPainter < ContainerPainter
         | 
| 7 | 
            +
                  def paint(canvas, left, top, &block)
         | 
| 8 | 
            +
                    super
         | 
| 9 | 
            +
                    canvas_coords = coords(left, top)
         | 
| 10 | 
            +
                    content_canvas = canvas.child(
         | 
| 11 | 
            +
                      canvas_coords.content_left,
         | 
| 12 | 
            +
                      canvas_coords.content_top,
         | 
| 13 | 
            +
                      dimensions.content_width,
         | 
| 14 | 
            +
                      dimensions.content_height
         | 
| 15 | 
            +
                    )
         | 
| 16 | 
            +
                    return unless content_canvas.writable?
         | 
| 17 | 
            +
                    if settings.horizontal_flow?
         | 
| 18 | 
            +
                      paint_horizontally(content_canvas, canvas_coords, &block)
         | 
| 19 | 
            +
                    else
         | 
| 20 | 
            +
                      paint_vertically(content_canvas, canvas_coords, &block)
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def dimensions
         | 
| 25 | 
            +
                    @dimensions ||= begin
         | 
| 26 | 
            +
                      content_width = 0
         | 
| 27 | 
            +
                      content_height = 0
         | 
| 28 | 
            +
                      if settings.horizontal_flow?
         | 
| 29 | 
            +
                        each_child do |child|
         | 
| 30 | 
            +
                          content_width += child.dimensions.outer_width
         | 
| 31 | 
            +
                          if child.dimensions.outer_height > content_height
         | 
| 32 | 
            +
                            content_height = child.dimensions.outer_height
         | 
| 33 | 
            +
                          end
         | 
| 34 | 
            +
                        end
         | 
| 35 | 
            +
                      else
         | 
| 36 | 
            +
                        each_child do |child|
         | 
| 37 | 
            +
                          if child.dimensions.outer_width > content_width
         | 
| 38 | 
            +
                            content_width = child.dimensions.outer_width
         | 
| 39 | 
            +
                          end
         | 
| 40 | 
            +
                          content_height += child.dimensions.outer_height
         | 
| 41 | 
            +
                        end
         | 
| 42 | 
            +
                      end
         | 
| 43 | 
            +
                      ContainerDimensions.new(settings, content_width, content_height)
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def each_child(&block)
         | 
| 48 | 
            +
                    if settings.reverse_flow?
         | 
| 49 | 
            +
                      children.reverse.each(&block)
         | 
| 50 | 
            +
                    else
         | 
| 51 | 
            +
                      super
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  private
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def paint_horizontally(canvas, canvas_coords, &block)
         | 
| 58 | 
            +
                    stroke_left = canvas_coords.content_left
         | 
| 59 | 
            +
                    stroke_top = canvas_coords.content_top
         | 
| 60 | 
            +
                    children_width = 0
         | 
| 61 | 
            +
                    each_child { |c| children_width += c.dimensions.outer_width }
         | 
| 62 | 
            +
                    left_offset, spacing_offset = horiz_justify_offset(children_width)
         | 
| 63 | 
            +
                    stroke_left += left_offset
         | 
| 64 | 
            +
                    each_child do |child|
         | 
| 65 | 
            +
                      top_offset, _ = vert_justify_offset(child.dimensions.outer_height)
         | 
| 66 | 
            +
                      child_width = child.dimensions.outer_width
         | 
| 67 | 
            +
                      child_canvas = canvas.child(
         | 
| 68 | 
            +
                        stroke_left,
         | 
| 69 | 
            +
                        stroke_top + top_offset,
         | 
| 70 | 
            +
                        child_width,
         | 
| 71 | 
            +
                        child.dimensions.outer_height
         | 
| 72 | 
            +
                      )
         | 
| 73 | 
            +
                      child.paint(child_canvas, stroke_left, stroke_top + top_offset, &block)
         | 
| 74 | 
            +
                      stroke_left += child_width + spacing_offset
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  def paint_vertically(canvas, canvas_coords, &block)
         | 
| 79 | 
            +
                    stroke_left = canvas_coords.content_left
         | 
| 80 | 
            +
                    stroke_top = canvas_coords.content_top
         | 
| 81 | 
            +
                    children_height = 0
         | 
| 82 | 
            +
                    each_child { |c| children_height += c.dimensions.outer_height }
         | 
| 83 | 
            +
                    top_offset, spacing_offset = vert_justify_offset(children_height)
         | 
| 84 | 
            +
                    stroke_top += top_offset
         | 
| 85 | 
            +
                    each_child do |child|
         | 
| 86 | 
            +
                      left_offset, _ = horiz_justify_offset(child.dimensions.outer_width)
         | 
| 87 | 
            +
                      child_height = child.dimensions.outer_height
         | 
| 88 | 
            +
                      child_canvas = canvas.child(
         | 
| 89 | 
            +
                        stroke_left + left_offset,
         | 
| 90 | 
            +
                        stroke_top ,
         | 
| 91 | 
            +
                        child.dimensions.outer_width,
         | 
| 92 | 
            +
                        child_height
         | 
| 93 | 
            +
                      )
         | 
| 94 | 
            +
                      child.paint(child_canvas, stroke_left + left_offset, stroke_top, &block)
         | 
| 95 | 
            +
                      stroke_top += child_height + spacing_offset
         | 
| 96 | 
            +
                    end
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
                private_constant :BoxPainter
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
            end
         |