boxybox 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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