boxybox 0.1.2

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.
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rake/extensiontask'
9
+
10
+ task build: :compile
11
+
12
+ Rake::ExtensionTask.new('boxybox') do |ext|
13
+ ext.lib_dir = 'lib/boxybox'
14
+ end
15
+
16
+ task default: %i[clobber compile spec]
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "boxybox"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'boxybox/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'boxybox'
9
+ spec.license = 'MIT'
10
+ spec.version = Boxybox::VERSION
11
+ spec.authors = ['Travis Carter']
12
+ spec.email = ['travis.carter79@outlook.com']
13
+
14
+ spec.summary = 'Box generator for an at home code challenge'
15
+ spec.description = 'Draws terminal ascii boxes, and boxes within boxes'
16
+ spec.homepage = 'https://github.com/phatjam98/boxybox'
17
+
18
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
19
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
20
+ if spec.respond_to?(:metadata)
21
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
22
+
23
+ spec.metadata['homepage_uri'] = spec.homepage
24
+ spec.metadata['source_code_uri'] = spec.homepage
25
+ spec.metadata['changelog_uri'] = spec.homepage
26
+ else
27
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
28
+ 'public gem pushes.'
29
+ end
30
+
31
+ # Specify which files should be added to the gem when it is released.
32
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
33
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
34
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
35
+ end
36
+ spec.bindir = 'exe'
37
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
38
+ spec.require_paths = ['lib']
39
+ spec.extensions = ['ext/boxybox/extconf.rb']
40
+ spec.required_ruby_version = '>2.6'
41
+
42
+ spec.add_dependency 'pastel', '~> 0.7.2'
43
+ spec.add_dependency 'thor', '~> 0.20.0'
44
+ spec.add_dependency 'tty-box', '~> 0.5.0'
45
+ spec.add_dependency 'tty-color', '~> 0.5'
46
+ spec.add_dependency 'tty-command', '~> 0.9.0'
47
+ spec.add_dependency 'tty-config', '~> 0.3.2'
48
+ spec.add_dependency 'tty-cursor', '~> 0.7'
49
+ spec.add_dependency 'tty-editor', '~> 0.5'
50
+ spec.add_dependency 'tty-file', '~> 0.8.0'
51
+ spec.add_dependency 'tty-font', '~> 0.4.0'
52
+ spec.add_dependency 'tty-logger', '~> 0.2.0'
53
+ spec.add_dependency 'tty-markdown', '~> 0.6.0'
54
+ spec.add_dependency 'tty-pager', '~> 0.12'
55
+ spec.add_dependency 'tty-pie', '~> 0.3.0'
56
+ spec.add_dependency 'tty-platform', '~> 0.2'
57
+ spec.add_dependency 'tty-progressbar', '~> 0.17'
58
+ spec.add_dependency 'tty-prompt', '~> 0.19'
59
+ spec.add_dependency 'tty-screen', '~> 0.7'
60
+ spec.add_dependency 'tty-spinner', '~> 0.9'
61
+ spec.add_dependency 'tty-table', '~> 0.11.0'
62
+ spec.add_dependency 'tty-tree', '~> 0.3'
63
+ spec.add_dependency 'tty-which', '~> 0.4'
64
+
65
+ spec.add_development_dependency 'bundler', '~> 1.17'
66
+ spec.add_development_dependency 'rake', '~> 10.0'
67
+ spec.add_development_dependency 'rake-compiler'
68
+ spec.add_development_dependency 'rspec', '~> 3.0'
69
+ spec.add_development_dependency 'rubocop', '~> 0.89.0'
70
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ lib_path = File.expand_path('../lib', __dir__)
5
+ $:.unshift(lib_path) if !$:.include?(lib_path)
6
+ require 'boxybox/cli'
7
+
8
+ Signal.trap('INT') do
9
+ warn("\n#{caller.join("\n")}: interrupted")
10
+ exit(1)
11
+ end
12
+
13
+ begin
14
+ Boxybox::CLI.start
15
+ rescue Boxybox::CLI::Error => err
16
+ puts "ERROR: #{err.message}"
17
+ exit 1
18
+ end
@@ -0,0 +1,9 @@
1
+ #include "boxybox.h"
2
+
3
+ VALUE rb_mBoxybox;
4
+
5
+ void
6
+ Init_boxybox(void)
7
+ {
8
+ rb_mBoxybox = rb_define_module("Boxybox");
9
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef BOXYBOX_H
2
+ #define BOXYBOX_H 1
3
+
4
+ #include "ruby.h"
5
+
6
+ #endif /* BOXYBOX_H */
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+
5
+ create_makefile('boxybox/boxybox')
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'boxybox/version'
4
+
5
+ module Boxybox
6
+ class Error < StandardError; end
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module Boxybox
6
+ # Handle the application command line parsing
7
+ # and the dispatch to various command objects
8
+ #
9
+ # @api public
10
+ class CLI < Thor
11
+ # Error raised by this runner
12
+ Error = Class.new(StandardError)
13
+
14
+ desc 'version', 'boxybox version'
15
+ def version
16
+ require_relative 'version'
17
+ puts "v#{Boxybox::VERSION}"
18
+ end
19
+ map %w(--version -v) => :version
20
+
21
+ desc 'boxes [INPUT]', 'Accepts a config as defined in the README and prints ASCII boxes in the terminal'
22
+ method_option :help, aliases: '-h', type: :boolean,
23
+ desc: 'Display usage information'
24
+ method_option :file, aliases: '-f', type: :string,
25
+ desc: 'Specify a file path to use as the input'
26
+ method_option :example, aliases: '-e', type: :string,
27
+ desc: 'Select example 1 to 4',
28
+ banner: 'example1', enum: %w(example1 example2 example3 example4)
29
+ method_option :print_example, aliases: '-p', type: :boolean,
30
+ desc: 'Select the example json to output to terminal.'
31
+
32
+ def boxes(input = nil)
33
+ if options[:help]
34
+ invoke :help, ['boxes']
35
+ else
36
+ require_relative 'commands/boxes'
37
+ Boxybox::Commands::Boxes.new(input, options).execute
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Boxybox
6
+ # This is generated from the TTY application bootstrap and is used to access the commands available to this app
7
+ class Command
8
+ extend Forwardable
9
+
10
+ def_delegators :command, :run
11
+
12
+ # Execute this command
13
+ #
14
+ # @api public
15
+ def execute(*)
16
+ raise(
17
+ NotImplementedError,
18
+ "#{self.class}##{__method__} must be implemented"
19
+ )
20
+ end
21
+
22
+ # The external commands runner
23
+ #
24
+ # @see http://www.rubydoc.info/gems/tty-command
25
+ #
26
+ # @api public
27
+ def command(**options)
28
+ require 'tty-command'
29
+ TTY::Command.new(options)
30
+ end
31
+
32
+ # The cursor movement
33
+ #
34
+ # @see http://www.rubydoc.info/gems/tty-cursor
35
+ #
36
+ # @api public
37
+ def cursor
38
+ require 'tty-cursor'
39
+ TTY::Cursor
40
+ end
41
+
42
+ # Open a file or text in the user's preferred editor
43
+ #
44
+ # @see http://www.rubydoc.info/gems/tty-editor
45
+ #
46
+ # @api public
47
+ def editor
48
+ require 'tty-editor'
49
+ TTY::Editor
50
+ end
51
+
52
+ # File manipulation utility methods
53
+ #
54
+ # @see http://www.rubydoc.info/gems/tty-file
55
+ #
56
+ # @api public
57
+ def generator
58
+ require 'tty-file'
59
+ TTY::File
60
+ end
61
+
62
+ # Terminal output paging
63
+ #
64
+ # @see http://www.rubydoc.info/gems/tty-pager
65
+ #
66
+ # @api public
67
+ def pager(**options)
68
+ require 'tty-pager'
69
+ TTY::Pager.new(options)
70
+ end
71
+
72
+ # Terminal platform and OS properties
73
+ #
74
+ # @see http://www.rubydoc.info/gems/tty-pager
75
+ #
76
+ # @api public
77
+ def platform
78
+ require 'tty-platform'
79
+ TTY::Platform.new
80
+ end
81
+
82
+ # The interactive prompt
83
+ #
84
+ # @see http://www.rubydoc.info/gems/tty-prompt
85
+ #
86
+ # @api public
87
+ def prompt(**options)
88
+ require 'tty-prompt'
89
+ TTY::Prompt.new(options)
90
+ end
91
+
92
+ # Get terminal screen properties
93
+ #
94
+ # @see http://www.rubydoc.info/gems/tty-screen
95
+ #
96
+ # @api public
97
+ def screen
98
+ require 'tty-screen'
99
+ TTY::Screen
100
+ end
101
+
102
+ # The unix which utility
103
+ #
104
+ # @see http://www.rubydoc.info/gems/tty-which
105
+ #
106
+ # @api public
107
+ def which(*args)
108
+ require 'tty-which'
109
+ TTY::Which.which(*args)
110
+ end
111
+
112
+ # Check if executable exists
113
+ #
114
+ # @see http://www.rubydoc.info/gems/tty-which
115
+ #
116
+ # @api public
117
+ def exec_exist?(*args)
118
+ require 'tty-which'
119
+ TTY::Which.exist?(*args)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1 @@
1
+ #
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+ require 'boxybox/models/box_builder'
5
+
6
+ module Boxybox
7
+ module Commands
8
+ class Boxes < Boxybox::Command
9
+ def initialize(input, options)
10
+ @input = input
11
+ @options = options
12
+ end
13
+
14
+ def execute(input: $stdin, output: $stdout)
15
+ json_str = @input
16
+
17
+ if @options['file']
18
+ file_path = @options['file']
19
+ json_str = IO.read(file_path)
20
+ elsif @options['example']
21
+ file_path = "lib/boxybox/templates/boxes/#{@options['example']}.json"
22
+ json_str = IO.read(file_path)
23
+ output.puts json_str if @options['print_example']
24
+ end
25
+
26
+ boxes = BoxBuilder.create_from_json(json_str)
27
+
28
+ # Command logic goes here ...
29
+ output.puts boxes
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'tty-box'
5
+
6
+ # @author Travis Carter
7
+ # helper methods to create and merge terminal boxes
8
+ class BoxBuilder
9
+ SPACE = ' '
10
+
11
+ attr_accessor :direction, :children, :content
12
+
13
+ # @param [Object] config
14
+ # @return [BoxBuilder] new instance of BoxBuilder
15
+ def initialize(config)
16
+ @direction = config['direction']
17
+ @children = config['children']
18
+ @content = config['content']
19
+ end
20
+
21
+ # This kicks off the parsing of the input JSON and returns the nested boxes as a string
22
+ # @param [JSON] json_string input to create boxes
23
+ # @return [String] will return a multiline string of ascii boxes
24
+ def self.create_from_json(json_string)
25
+ config = JSON.parse(json_string)
26
+ box_builder = BoxBuilder.new(config['boxes'])
27
+
28
+ box_builder.create_boxes
29
+ end
30
+
31
+ # This is the recursive method that craws down the tree to create the boxes
32
+ # @return [Strings]
33
+ def create_boxes
34
+ unless @children.nil?
35
+ child_boxes = []
36
+
37
+ children.each { |child| child_boxes << BoxBuilder.new(child).create_boxes }
38
+
39
+ @content = if child_boxes.length > 1 && direction == 'horizontal'
40
+ BoxBuilder.merge_boxes(*child_boxes)
41
+ else
42
+ child_boxes.join("\n")
43
+ end
44
+ end
45
+
46
+ @content = make_box(@content)
47
+ end
48
+
49
+ # Wrapper around the TTY::Box module. This will be a prime target for expanded style choices and using more of the
50
+ # customizations available within the TTY gem set
51
+ # @return [Strings] ascii box
52
+ def make_box(content)
53
+ TTY::Box.frame(content, padding: 1, border: :ascii)
54
+ end
55
+
56
+ # @param [Array] box_strings boxes to be merged
57
+ # @return [String]
58
+ def self.merge_boxes(*box_strings)
59
+ box_arrays = {}
60
+ max_rows = 0
61
+ new_box = []
62
+
63
+ box_strings.each_with_index do |box, idx|
64
+ box_arrays[idx] = box.split("\n")
65
+
66
+ max_rows = max_rows > box_arrays[idx].length ? max_rows : box_arrays[idx].length
67
+ end
68
+
69
+ max_rows.times do |x|
70
+ new_line = ''
71
+ box_arrays.each_value { |box| new_line += box[x].nil? ? SPACE * box.first.length : box[x] }
72
+
73
+ new_box << new_line
74
+ end
75
+
76
+ new_box.join("\n")
77
+ end
78
+ end