megingiard 0.0.1
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 +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +11 -0
- data/Gemfile.devtools +71 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +6 -0
- data/config/devtools.yml +4 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +4 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +104 -0
- data/config/rubocop.yml +49 -0
- data/config/yardstick.yml +2 -0
- data/lib/megingiard.rb +6 -0
- data/lib/megingiard/ansi_colors.rb +21 -0
- data/lib/megingiard/ansi_escape_code_validator.rb +20 -0
- data/lib/megingiard/ansi_escape_sequence.rb +16 -0
- data/lib/megingiard/bold_node.rb +16 -0
- data/lib/megingiard/bold_sequence.rb +7 -0
- data/lib/megingiard/centered_canvas.rb +45 -0
- data/lib/megingiard/centered_node.rb +13 -0
- data/lib/megingiard/color_node.rb +17 -0
- data/lib/megingiard/emoji_node.rb +16 -0
- data/lib/megingiard/emojis.rb +12 -0
- data/lib/megingiard/hash_wrapper.rb +16 -0
- data/lib/megingiard/node.rb +13 -0
- data/lib/megingiard/reset_sequence.rb +7 -0
- data/lib/megingiard/terminal_width.rb +11 -0
- data/lib/megingiard/text_color_sequence.rb +17 -0
- data/lib/megingiard/version.rb +4 -0
- data/megingiard.gemspec +23 -0
- data/spec/integration/nodes_spec.rb +23 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/ansi_escape_code_validator/validate_spec.rb +20 -0
- data/spec/unit/ansi_escape_sequence/initialize_spec.rb +18 -0
- data/spec/unit/ansi_escape_sequence/to_s_spec.rb +27 -0
- data/spec/unit/bold_sequence/to_s_spec.rb +24 -0
- data/spec/unit/centered_canvas/draw_centered_row_spec.rb +50 -0
- data/spec/unit/centered_canvas/draw_left_column_spec.rb +40 -0
- data/spec/unit/centered_canvas/draw_right_column_spec.rb +54 -0
- data/spec/unit/centered_canvas/initialize_spec.rb +11 -0
- data/spec/unit/color_node/to_s_spec.rb +29 -0
- data/spec/unit/emoji_node/to_s_spec.rb +20 -0
- data/spec/unit/hash_wrapper/fetch_spec.rb +34 -0
- data/spec/unit/node/to_s_spec.rb +29 -0
- data/spec/unit/text_color_sequence/initialize_spec.rb +24 -0
- data/spec/unit/text_color_sequence/to_s_spec.rb +26 -0
- metadata +139 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: ae5d046438bb7e1363e26703dd5b52d3eb6e7005
|
|
4
|
+
data.tar.gz: edcb50b4fe7753b5a56063abb983704bdd96da48
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 13070715b9ebb020440d20a2610de16a981fc04d0bc1525cb53399029b79855273a525d0483dc2bb1ae86fdcf8beda89008740cc9f46f94ecd3d778e193b63f3
|
|
7
|
+
data.tar.gz: 37c6bc40b8eb538c9b07aa74d2fd604b495407482c264e9d8e7f975da6733516888e90712de68f4dd789dfba88c52984433d072894edd449f21f5ce02ba84d52
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.0.0-p451
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
source 'https://rubygems.org'
|
|
3
|
+
|
|
4
|
+
# Specify your gem's dependencies in megingiard.gemspec
|
|
5
|
+
gemspec
|
|
6
|
+
|
|
7
|
+
group :development, :test do
|
|
8
|
+
gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
eval_gemfile 'Gemfile.devtools'
|
data/Gemfile.devtools
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
group :development do
|
|
4
|
+
gem 'rake', '~> 10.2.1'
|
|
5
|
+
gem 'rspec', '~> 2.14.1'
|
|
6
|
+
gem 'rspec-core', '~> 2.14.8'
|
|
7
|
+
gem 'yard', '~> 0.8.7.4'
|
|
8
|
+
|
|
9
|
+
platform :rbx do
|
|
10
|
+
gem 'rubysl-singleton', '~> 2.0.0'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
group :yard do
|
|
15
|
+
gem 'kramdown', '~> 1.3.3'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
group :guard do
|
|
19
|
+
gem 'guard', '~> 2.6.0'
|
|
20
|
+
gem 'guard-bundler', '~> 2.0.0'
|
|
21
|
+
gem 'guard-rspec', '~> 4.2.8'
|
|
22
|
+
gem 'guard-rubocop', '~> 1.0.2'
|
|
23
|
+
|
|
24
|
+
# file system change event handling
|
|
25
|
+
gem 'listen', '~> 2.7.1'
|
|
26
|
+
gem 'rb-fchange', '~> 0.0.6', require: false
|
|
27
|
+
gem 'rb-fsevent', '~> 0.9.4', require: false
|
|
28
|
+
gem 'rb-inotify', '~> 0.9.3', require: false
|
|
29
|
+
|
|
30
|
+
# notification handling
|
|
31
|
+
gem 'libnotify', '~> 0.8.2', require: false
|
|
32
|
+
gem 'rb-notifu', '~> 0.0.4', require: false
|
|
33
|
+
gem 'terminal-notifier-guard', '~> 1.5.3', require: false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
group :metrics do
|
|
37
|
+
gem 'coveralls', '~> 0.7.0'
|
|
38
|
+
gem 'flay', '~> 2.4.0'
|
|
39
|
+
gem 'flog', '~> 4.2.0'
|
|
40
|
+
gem 'reek', '~> 1.3.7'
|
|
41
|
+
gem 'rubocop', '~> 0.19.1'
|
|
42
|
+
gem 'simplecov', '~> 0.8.2'
|
|
43
|
+
gem 'yardstick', '~> 0.9.9'
|
|
44
|
+
|
|
45
|
+
platforms :mri do
|
|
46
|
+
gem 'mutant', '~> 0.5.9'
|
|
47
|
+
gem 'mutant-rspec', '~> 0.5.3'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
platforms :ruby_19, :ruby_20 do
|
|
51
|
+
gem 'yard-spellcheck', '~> 0.1.5'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
platform :rbx do
|
|
55
|
+
gem 'json', '~> 1.8.1'
|
|
56
|
+
gem 'racc', '~> 1.4.11'
|
|
57
|
+
gem 'rubysl-logger', '~> 2.0.0'
|
|
58
|
+
gem 'rubysl-open-uri', '~> 2.0.0'
|
|
59
|
+
gem 'rubysl-prettyprint', '~> 2.0.3'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
group :benchmarks do
|
|
64
|
+
gem 'rbench', '~> 0.2.3'
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
platform :jruby do
|
|
68
|
+
group :jruby do
|
|
69
|
+
gem 'jruby-openssl', '~> 0.8.5'
|
|
70
|
+
end
|
|
71
|
+
end
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 Lucas Dohmen
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Megingiard
|
|
2
|
+
|
|
3
|
+
Tools for creating beautiful CLI output.
|
|
4
|
+
|
|
5
|
+
> Megingjörð is a belt worn by the god [Thor](https://en.wikipedia.org/wiki/Thor). According to the [Prose Edda](https://en.wikipedia.org/wiki/Prose_Edda), the belt is one of Thor's three main possessions, along with the hammer Mjölnir and the iron gloves Járngreipr. When worn, the belt is described as doubling Thor's already prodigious strength.
|
|
6
|
+
– Wikipedia
|
|
7
|
+
|
|
8
|
+
This is a work-in-progress library to create nice reporting output on the terminal. It will be used in exogenesis, but with later versions will hopefully be useful to other libraries as well. It is written with the help of [devtools](https://github.com/rom-rb/devtools) – this is mainly an experiment on which metrics I like for everyday development.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Add this line to your application's Gemfile:
|
|
13
|
+
|
|
14
|
+
gem 'megingiard'
|
|
15
|
+
|
|
16
|
+
And then execute:
|
|
17
|
+
|
|
18
|
+
$ bundle
|
|
19
|
+
|
|
20
|
+
Or install it yourself as:
|
|
21
|
+
|
|
22
|
+
$ gem install megingiard
|
|
23
|
+
|
|
24
|
+
## Contributing
|
|
25
|
+
|
|
26
|
+
1. Fork it
|
|
27
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
28
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
29
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
30
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/config/devtools.yml
ADDED
data/config/flay.yml
ADDED
data/config/flog.yml
ADDED
data/config/mutant.yml
ADDED
data/config/reek.yml
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
Attribute:
|
|
3
|
+
enabled: true
|
|
4
|
+
exclude: []
|
|
5
|
+
BooleanParameter:
|
|
6
|
+
enabled: true
|
|
7
|
+
exclude: []
|
|
8
|
+
ClassVariable:
|
|
9
|
+
enabled: true
|
|
10
|
+
exclude: []
|
|
11
|
+
ControlParameter:
|
|
12
|
+
enabled: true
|
|
13
|
+
exclude:
|
|
14
|
+
- Megingiard::AnsiEscapeCodeValidator#validate
|
|
15
|
+
DataClump:
|
|
16
|
+
enabled: true
|
|
17
|
+
exclude: []
|
|
18
|
+
max_copies: 2
|
|
19
|
+
min_clump_size: 2
|
|
20
|
+
DuplicateMethodCall:
|
|
21
|
+
enabled: true
|
|
22
|
+
exclude: []
|
|
23
|
+
max_calls: 1
|
|
24
|
+
allow_calls: []
|
|
25
|
+
FeatureEnvy:
|
|
26
|
+
enabled: true
|
|
27
|
+
exclude: []
|
|
28
|
+
IrresponsibleModule:
|
|
29
|
+
enabled: true
|
|
30
|
+
exclude: []
|
|
31
|
+
LongParameterList:
|
|
32
|
+
enabled: true
|
|
33
|
+
exclude: []
|
|
34
|
+
max_params: 2
|
|
35
|
+
overrides:
|
|
36
|
+
initialize:
|
|
37
|
+
max_params: 3
|
|
38
|
+
LongYieldList:
|
|
39
|
+
enabled: true
|
|
40
|
+
exclude: []
|
|
41
|
+
max_params: 2
|
|
42
|
+
NestedIterators:
|
|
43
|
+
enabled: true
|
|
44
|
+
exclude: []
|
|
45
|
+
max_allowed_nesting: 1
|
|
46
|
+
ignore_iterators: []
|
|
47
|
+
NilCheck:
|
|
48
|
+
enabled: true
|
|
49
|
+
exclude: []
|
|
50
|
+
RepeatedConditional:
|
|
51
|
+
enabled: true
|
|
52
|
+
exclude: []
|
|
53
|
+
max_ifs: 1
|
|
54
|
+
TooManyInstanceVariables:
|
|
55
|
+
enabled: true
|
|
56
|
+
exclude: []
|
|
57
|
+
max_instance_variables: 3
|
|
58
|
+
TooManyMethods:
|
|
59
|
+
enabled: true
|
|
60
|
+
exclude: []
|
|
61
|
+
max_methods: 10
|
|
62
|
+
TooManyStatements:
|
|
63
|
+
enabled: true
|
|
64
|
+
exclude:
|
|
65
|
+
- each
|
|
66
|
+
max_statements: 3
|
|
67
|
+
UncommunicativeMethodName:
|
|
68
|
+
enabled: true
|
|
69
|
+
exclude: []
|
|
70
|
+
reject:
|
|
71
|
+
- !ruby/regexp /^[a-z]$/
|
|
72
|
+
- !ruby/regexp /[0-9]$/
|
|
73
|
+
- !ruby/regexp /[A-Z]/
|
|
74
|
+
accept: []
|
|
75
|
+
UncommunicativeModuleName:
|
|
76
|
+
enabled: true
|
|
77
|
+
exclude: []
|
|
78
|
+
reject:
|
|
79
|
+
- !ruby/regexp /^.$/
|
|
80
|
+
- !ruby/regexp /[0-9]$/
|
|
81
|
+
accept: []
|
|
82
|
+
UncommunicativeParameterName:
|
|
83
|
+
enabled: true
|
|
84
|
+
exclude: []
|
|
85
|
+
reject:
|
|
86
|
+
- !ruby/regexp /^.$/
|
|
87
|
+
- !ruby/regexp /[0-9]$/
|
|
88
|
+
- !ruby/regexp /[A-Z]/
|
|
89
|
+
accept: []
|
|
90
|
+
UncommunicativeVariableName:
|
|
91
|
+
enabled: true
|
|
92
|
+
exclude: []
|
|
93
|
+
reject:
|
|
94
|
+
- !ruby/regexp /^.$/
|
|
95
|
+
- !ruby/regexp /[0-9]$/
|
|
96
|
+
- !ruby/regexp /[A-Z]/
|
|
97
|
+
accept: []
|
|
98
|
+
UnusedParameters:
|
|
99
|
+
enabled: true
|
|
100
|
+
exclude: []
|
|
101
|
+
UtilityFunction:
|
|
102
|
+
enabled: true
|
|
103
|
+
exclude: []
|
|
104
|
+
max_helper_calls: 0
|
data/config/rubocop.yml
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
Includes:
|
|
3
|
+
- '**/*.rake'
|
|
4
|
+
- 'Gemfile'
|
|
5
|
+
- 'Gemfile.devtools'
|
|
6
|
+
Excludes:
|
|
7
|
+
- '**/vendor/**'
|
|
8
|
+
- '**/benchmarks/**'
|
|
9
|
+
|
|
10
|
+
# Avoid parameter lists longer than five parameters.
|
|
11
|
+
ParameterLists:
|
|
12
|
+
Max: 3
|
|
13
|
+
CountKeywordArgs: true
|
|
14
|
+
|
|
15
|
+
# Avoid more than `Max` levels of nesting.
|
|
16
|
+
BlockNesting:
|
|
17
|
+
Max: 3
|
|
18
|
+
|
|
19
|
+
# Align with the style guide.
|
|
20
|
+
CollectionMethods:
|
|
21
|
+
PreferredMethods:
|
|
22
|
+
collect: 'map'
|
|
23
|
+
inject: 'reduce'
|
|
24
|
+
find: 'detect'
|
|
25
|
+
find_all: 'select'
|
|
26
|
+
|
|
27
|
+
# Limit line length
|
|
28
|
+
LineLength:
|
|
29
|
+
Max: 100
|
|
30
|
+
|
|
31
|
+
# Disable documentation checking until a class needs to be documented once
|
|
32
|
+
Documentation:
|
|
33
|
+
Enabled: false
|
|
34
|
+
|
|
35
|
+
# Do not favor modifier if/unless usage when you have a single-line body
|
|
36
|
+
IfUnlessModifier:
|
|
37
|
+
Enabled: false
|
|
38
|
+
|
|
39
|
+
# Allow case equality operator (in limited use within the specs)
|
|
40
|
+
CaseEquality:
|
|
41
|
+
Enabled: false
|
|
42
|
+
|
|
43
|
+
# Constants do not always have to use SCREAMING_SNAKE_CASE
|
|
44
|
+
ConstantName:
|
|
45
|
+
Enabled: false
|
|
46
|
+
|
|
47
|
+
# Not all trivial readers/writers can be defined with attr_* methods
|
|
48
|
+
TrivialAccessors:
|
|
49
|
+
Enabled: false
|
data/lib/megingiard.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/hash_wrapper'
|
|
3
|
+
|
|
4
|
+
module Megingiard
|
|
5
|
+
# The given ANSI escape sequence was not valid
|
|
6
|
+
class InvalidAnsiColorCode < ArgumentError
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
ANSI_COLOR_MAP = {
|
|
10
|
+
red: 1,
|
|
11
|
+
green: 2,
|
|
12
|
+
yellow: 3,
|
|
13
|
+
blue: 4,
|
|
14
|
+
magenta: 5,
|
|
15
|
+
cyan: 6,
|
|
16
|
+
white: 7
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# Color codes for ANSI color names
|
|
20
|
+
ANSI_COLORS = HashWrapper.new(ANSI_COLOR_MAP, InvalidAnsiColorCode)
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'singleton'
|
|
3
|
+
|
|
4
|
+
module Megingiard
|
|
5
|
+
# The given ANSI escape sequence was not valid
|
|
6
|
+
class InvalidAnsiEscapeCode < ArgumentError
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Validator for ANSI escape sequence
|
|
10
|
+
class AnsiEscapeCodeValidator
|
|
11
|
+
include Singleton
|
|
12
|
+
|
|
13
|
+
VALID_ESCAPE_CODES = 0..55
|
|
14
|
+
|
|
15
|
+
# Validate an ANSI escape sequence
|
|
16
|
+
def validate(code)
|
|
17
|
+
fail InvalidAnsiEscapeCode unless VALID_ESCAPE_CODES.include?(code)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/ansi_escape_code_validator'
|
|
3
|
+
|
|
4
|
+
module Megingiard
|
|
5
|
+
# As the name suggests
|
|
6
|
+
class AnsiEscapeSequence
|
|
7
|
+
def initialize(code)
|
|
8
|
+
AnsiEscapeCodeValidator.instance.validate(code)
|
|
9
|
+
@code = code
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
"\e[#{@code}m"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/bold_sequence'
|
|
3
|
+
require 'megingiard/reset_sequence'
|
|
4
|
+
|
|
5
|
+
module Megingiard
|
|
6
|
+
# A node that makes all its children bold
|
|
7
|
+
class BoldNode
|
|
8
|
+
def initialize(child)
|
|
9
|
+
@child = child
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
"#{BOLD_SEQUENCE}#{@child}#{RESET_SEQUENCE}"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/terminal_width'
|
|
3
|
+
require 'megingiard/node'
|
|
4
|
+
require 'megingiard/centered_node'
|
|
5
|
+
|
|
6
|
+
module Megingiard
|
|
7
|
+
# An area that can be drawn on, everything is centered
|
|
8
|
+
class CenteredCanvas
|
|
9
|
+
def initialize(output)
|
|
10
|
+
@output = output
|
|
11
|
+
@left_column_drawn = false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Check if a left column has been drawn
|
|
15
|
+
def left_column_drawn?
|
|
16
|
+
@left_column_drawn
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# The left half of a full-width row with right aligned content
|
|
20
|
+
def draw_left_column(node)
|
|
21
|
+
right_adjusted_text = node.to_s.rjust(CELL_WIDTH)
|
|
22
|
+
@output.print right_adjusted_text
|
|
23
|
+
@left_column_drawn = true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# The right half of a full-width row
|
|
27
|
+
def draw_right_column(node)
|
|
28
|
+
node = Node.new(EMPTY_CELL, node) unless left_column_drawn?
|
|
29
|
+
end_line_with(node)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# A full-width row where the content is centered
|
|
33
|
+
def draw_centered_row(node)
|
|
34
|
+
node = CenteredNode.new(TERMINAL_WIDTH, node)
|
|
35
|
+
end_line_with(node)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def end_line_with(element)
|
|
41
|
+
@output.puts(element.to_s)
|
|
42
|
+
@left_column_drawn = false
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/text_color_sequence'
|
|
3
|
+
require 'megingiard/reset_sequence'
|
|
4
|
+
|
|
5
|
+
module Megingiard
|
|
6
|
+
# A node that colors all its children in a given color
|
|
7
|
+
class ColorNode
|
|
8
|
+
def initialize(color_name, child)
|
|
9
|
+
@color_sequence = TextColorSequence.new(color_name)
|
|
10
|
+
@child = child
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_s
|
|
14
|
+
"#{@color_sequence}#{@child}#{RESET_SEQUENCE}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/emojis'
|
|
3
|
+
require 'megingiard/reset_sequence'
|
|
4
|
+
|
|
5
|
+
module Megingiard
|
|
6
|
+
# A leaf node representing an emoji
|
|
7
|
+
class EmojiNode
|
|
8
|
+
def initialize(emoji_name)
|
|
9
|
+
@emoji = EMOJIS.fetch(emoji_name)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
@emoji
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'utf8_emoji'
|
|
3
|
+
require 'megingiard/hash_wrapper'
|
|
4
|
+
|
|
5
|
+
module Megingiard
|
|
6
|
+
# There is no Emoji known with this name
|
|
7
|
+
class InvalidEmojiName < ArgumentError
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Name to Emoji Wrapper
|
|
11
|
+
EMOJIS = HashWrapper.new(Utf8Emoji.emojis, InvalidEmojiName)
|
|
12
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
module Megingiard
|
|
3
|
+
# Only reveal fetch and translates the Error Message
|
|
4
|
+
class HashWrapper
|
|
5
|
+
def initialize(hash, error_class)
|
|
6
|
+
@hash = hash
|
|
7
|
+
@error_class = error_class
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def fetch(name)
|
|
11
|
+
@hash.fetch(name)
|
|
12
|
+
rescue
|
|
13
|
+
raise @error_class
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
module Megingiard
|
|
3
|
+
# The width of the terminal
|
|
4
|
+
TERMINAL_WIDTH = Integer(`tput cols`)
|
|
5
|
+
|
|
6
|
+
# A Cell has half of the width of the terminal
|
|
7
|
+
CELL_WIDTH = TERMINAL_WIDTH / 2
|
|
8
|
+
|
|
9
|
+
# A Cell filled with whitespace
|
|
10
|
+
EMPTY_CELL = ' ' * CELL_WIDTH
|
|
11
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/ansi_colors'
|
|
3
|
+
require 'megingiard/ansi_escape_sequence'
|
|
4
|
+
|
|
5
|
+
module Megingiard
|
|
6
|
+
# ANSI Escape Sequence for a Text Color
|
|
7
|
+
class TextColorSequence
|
|
8
|
+
def initialize(name)
|
|
9
|
+
color_code = ANSI_COLORS.fetch(name)
|
|
10
|
+
@escape_sequence = AnsiEscapeSequence.new(color_code + 30)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_s
|
|
14
|
+
@escape_sequence.to_s
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/megingiard.gemspec
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'megingiard/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "megingiard"
|
|
8
|
+
spec.version = Megingiard::VERSION
|
|
9
|
+
spec.authors = ["moonglum"]
|
|
10
|
+
spec.email = ["moonglum@moonbeamlabs.com"]
|
|
11
|
+
spec.description = %q{Tools for creating beautiful CLI output}
|
|
12
|
+
spec.summary = %q{This gem provides beautiful output for your CLI}
|
|
13
|
+
spec.homepage = ""
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files`.split($/)
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_dependency "utf8_emoji", "~> 0.1.0"
|
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.6.0"
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/node'
|
|
3
|
+
require 'megingiard/color_node'
|
|
4
|
+
require 'megingiard/bold_node'
|
|
5
|
+
require 'megingiard/emoji_node'
|
|
6
|
+
|
|
7
|
+
describe 'Nodes' do
|
|
8
|
+
it 'should combine color, bold and normal nodes' do
|
|
9
|
+
red_node = Megingiard::ColorNode.new(:red, 'rot')
|
|
10
|
+
text_node = Megingiard::Node.new('Dieser Text ist ', red_node)
|
|
11
|
+
bold_node = Megingiard::BoldNode.new(text_node)
|
|
12
|
+
|
|
13
|
+
expect(bold_node.to_s).to eq "\e[1mDieser Text ist \e[31mrot\e[0m\e[0m"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'should add an Emoji to colored text' do
|
|
17
|
+
emoji_node = Megingiard::EmojiNode.new(:rocket)
|
|
18
|
+
node = Megingiard::Node.new('This is ', emoji_node, ' science')
|
|
19
|
+
green_node = Megingiard::ColorNode.new(:green, node)
|
|
20
|
+
|
|
21
|
+
expect(green_node.to_s).to eq("\e[32mThis is 🚀 science\e[0m")
|
|
22
|
+
end
|
|
23
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/ansi_escape_code_validator'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::AnsiEscapeCodeValidator do
|
|
5
|
+
subject { Megingiard::AnsiEscapeCodeValidator.instance }
|
|
6
|
+
|
|
7
|
+
describe 'validate' do
|
|
8
|
+
it 'should throw an exception if the sequence is too high' do
|
|
9
|
+
expect do
|
|
10
|
+
subject.validate(56)
|
|
11
|
+
end.to raise_error(Megingiard::InvalidAnsiEscapeCode)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'should not throw an exception if the code is ok' do
|
|
15
|
+
expect do
|
|
16
|
+
subject.validate(0)
|
|
17
|
+
end.not_to raise_error
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/ansi_escape_sequence'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::AnsiEscapeSequence do
|
|
5
|
+
subject { Megingiard::AnsiEscapeSequence }
|
|
6
|
+
let(:validator) { double }
|
|
7
|
+
let(:code) { double }
|
|
8
|
+
|
|
9
|
+
describe 'initialize' do
|
|
10
|
+
it 'should validate the escape sequence' do
|
|
11
|
+
allow(Megingiard::AnsiEscapeCodeValidator).to receive(:instance)
|
|
12
|
+
.and_return(validator)
|
|
13
|
+
expect(validator).to receive(:validate).with(code)
|
|
14
|
+
|
|
15
|
+
subject.new(code)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/ansi_escape_sequence'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::AnsiEscapeSequence do
|
|
5
|
+
let(:code) { double('Integer', to_s: code_as_string) }
|
|
6
|
+
let(:code_as_string) { '1' }
|
|
7
|
+
let(:validator) { double }
|
|
8
|
+
|
|
9
|
+
subject { Megingiard::AnsiEscapeSequence.new(code) }
|
|
10
|
+
|
|
11
|
+
before do
|
|
12
|
+
allow(Megingiard::AnsiEscapeCodeValidator).to receive(:instance)
|
|
13
|
+
.and_return(validator)
|
|
14
|
+
allow(validator).to receive(:validate)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe 'to_s' do
|
|
18
|
+
it 'should convert the code into a string' do
|
|
19
|
+
expect(code).to receive(:to_s)
|
|
20
|
+
subject.to_s
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'should return the code as an escape sequence' do
|
|
24
|
+
expect(subject.to_s).to eq "\e[#{code_as_string}m"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/bold_node'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::BoldNode do
|
|
5
|
+
subject { Megingiard::BoldNode.new(child) }
|
|
6
|
+
let(:child) { double(String, to_s: child_string) }
|
|
7
|
+
let(:child_string) { double }
|
|
8
|
+
let(:reset_sequence_string) { double }
|
|
9
|
+
let(:bold_sequence_string) { double }
|
|
10
|
+
let(:expected_sequence) { "#{Megingiard::BOLD_SEQUENCE}#{child}#{Megingiard::RESET_SEQUENCE}" }
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
allow(Megingiard::RESET_SEQUENCE).to receive(:to_s)
|
|
14
|
+
.and_return(reset_sequence_string)
|
|
15
|
+
allow(Megingiard::BOLD_SEQUENCE).to receive(:to_s)
|
|
16
|
+
.and_return(bold_sequence_string)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe 'to_s' do
|
|
20
|
+
it 'should wrap the child in a bold and a reset sequence' do
|
|
21
|
+
expect(subject.to_s).to eq expected_sequence
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/centered_canvas'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::CenteredCanvas do
|
|
5
|
+
subject { Megingiard::CenteredCanvas.new(output) }
|
|
6
|
+
let(:node) { double }
|
|
7
|
+
let(:node_as_string) { double }
|
|
8
|
+
let(:centered_text) { double }
|
|
9
|
+
let(:output) { double }
|
|
10
|
+
let(:terminal_width) { double }
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
stub_const('Megingiard::TERMINAL_WIDTH', terminal_width)
|
|
14
|
+
allow(node).to receive(:to_s)
|
|
15
|
+
.and_return(node_as_string)
|
|
16
|
+
allow(node_as_string).to receive(:center)
|
|
17
|
+
.and_return(centered_text)
|
|
18
|
+
allow(centered_text).to receive(:to_s)
|
|
19
|
+
.and_return(centered_text)
|
|
20
|
+
allow(output).to receive(:puts)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe 'draw_centered_row' do
|
|
24
|
+
context 'left column was not drawn' do
|
|
25
|
+
before { subject.instance_variable_set('@left_column_drawn', false) }
|
|
26
|
+
|
|
27
|
+
it 'should to_s and center the text' do
|
|
28
|
+
expect(node_as_string).to receive(:center)
|
|
29
|
+
.with(terminal_width)
|
|
30
|
+
subject.draw_centered_row(node)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'left column was drawn' do
|
|
35
|
+
before { subject.instance_variable_set('@left_column_drawn', true) }
|
|
36
|
+
|
|
37
|
+
it 'should know that it has not drawn a left column' do
|
|
38
|
+
expect do
|
|
39
|
+
subject.draw_centered_row(node)
|
|
40
|
+
end.to change { subject.left_column_drawn? }.to(false)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'should put the resulting text to the output' do
|
|
44
|
+
expect(output).to receive(:puts)
|
|
45
|
+
.with(centered_text)
|
|
46
|
+
subject.draw_centered_row(node)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/centered_canvas'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::CenteredCanvas do
|
|
5
|
+
subject { Megingiard::CenteredCanvas.new(output) }
|
|
6
|
+
let(:node) { double }
|
|
7
|
+
let(:node_as_string) { double }
|
|
8
|
+
let(:right_adjusted_text) { double }
|
|
9
|
+
let(:output) { double }
|
|
10
|
+
let(:cell_width) { double }
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
stub_const('Megingiard::CELL_WIDTH', cell_width)
|
|
14
|
+
allow(node).to receive(:to_s)
|
|
15
|
+
.and_return(node_as_string)
|
|
16
|
+
allow(node_as_string).to receive(:rjust)
|
|
17
|
+
.and_return(right_adjusted_text)
|
|
18
|
+
allow(output).to receive(:print)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe 'draw_left_column' do
|
|
22
|
+
it 'should to_s and right adjust the text' do
|
|
23
|
+
expect(node_as_string).to receive(:rjust)
|
|
24
|
+
.with(cell_width)
|
|
25
|
+
subject.draw_left_column(node)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'should print the resulting text to the output' do
|
|
29
|
+
expect(output).to receive(:print)
|
|
30
|
+
.with(right_adjusted_text)
|
|
31
|
+
subject.draw_left_column(node)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'should know that it has drawn a left column' do
|
|
35
|
+
expect do
|
|
36
|
+
subject.draw_left_column(node)
|
|
37
|
+
end.to change { subject.left_column_drawn? }.to(true)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/centered_canvas'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::CenteredCanvas do
|
|
5
|
+
subject { Megingiard::CenteredCanvas.new(output) }
|
|
6
|
+
let(:node) { double }
|
|
7
|
+
let(:node_as_string) { double }
|
|
8
|
+
let(:centered_text) { double }
|
|
9
|
+
let(:output) { double }
|
|
10
|
+
let(:terminal_width) { double }
|
|
11
|
+
let(:wrapped_node) { double }
|
|
12
|
+
let(:wrapped_node_as_string) { double }
|
|
13
|
+
|
|
14
|
+
before do
|
|
15
|
+
stub_const('Megingiard::TERMINAL_WIDTH', terminal_width)
|
|
16
|
+
allow(node).to receive(:to_s)
|
|
17
|
+
.and_return(node_as_string)
|
|
18
|
+
allow(output).to receive(:puts)
|
|
19
|
+
allow(wrapped_node).to receive(:to_s)
|
|
20
|
+
.and_return(wrapped_node_as_string)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe 'draw_centered_row' do
|
|
24
|
+
context 'left column drawn' do
|
|
25
|
+
before { subject.instance_variable_set('@left_column_drawn', true) }
|
|
26
|
+
|
|
27
|
+
it 'should put the resulting text to the output' do
|
|
28
|
+
expect(output).to receive(:puts)
|
|
29
|
+
.with(node_as_string)
|
|
30
|
+
subject.draw_right_column(node)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'should know that it has not drawn a left column' do
|
|
34
|
+
expect do
|
|
35
|
+
subject.draw_right_column(node)
|
|
36
|
+
end.to change { subject.left_column_drawn? }.to(false)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context 'left column not drawn' do
|
|
41
|
+
before { subject.instance_variable_set('@left_column_drawn', false) }
|
|
42
|
+
|
|
43
|
+
it 'should prepend an empty cell to the output' do
|
|
44
|
+
allow(Megingiard::Node).to receive(:new)
|
|
45
|
+
.with(Megingiard::EMPTY_CELL, node)
|
|
46
|
+
.and_return(wrapped_node)
|
|
47
|
+
|
|
48
|
+
expect(output).to receive(:puts)
|
|
49
|
+
.with(wrapped_node_as_string)
|
|
50
|
+
subject.draw_right_column(node)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/centered_canvas'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::CenteredCanvas do
|
|
5
|
+
subject { Megingiard::CenteredCanvas.new(output) }
|
|
6
|
+
let(:output) { double }
|
|
7
|
+
|
|
8
|
+
describe 'initialize' do
|
|
9
|
+
its(:left_column_drawn?) { should be false }
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/color_node'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::ColorNode do
|
|
5
|
+
subject { Megingiard::ColorNode.new(color_name, child) }
|
|
6
|
+
let(:color_name) { double }
|
|
7
|
+
let(:child) { double(String, to_s: child_string) }
|
|
8
|
+
let(:child_string) { double }
|
|
9
|
+
let(:text_color_sequence) do
|
|
10
|
+
double(Megingiard::TextColorSequence, to_s: text_color_sequence_string)
|
|
11
|
+
end
|
|
12
|
+
let(:reset_sequence_string) { double }
|
|
13
|
+
let(:text_color_sequence_string) { double }
|
|
14
|
+
|
|
15
|
+
before do
|
|
16
|
+
allow(Megingiard::TextColorSequence).to receive(:new)
|
|
17
|
+
.with(color_name)
|
|
18
|
+
.and_return(text_color_sequence)
|
|
19
|
+
allow(Megingiard::RESET_SEQUENCE).to receive(:to_s)
|
|
20
|
+
.and_return(reset_sequence_string)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe 'to_s' do
|
|
24
|
+
it 'should be awesome' do
|
|
25
|
+
sequence = "#{text_color_sequence}#{child}#{Megingiard::RESET_SEQUENCE}"
|
|
26
|
+
expect(subject.to_s).to eq sequence
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/emoji_node'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::EmojiNode do
|
|
5
|
+
subject { Megingiard::EmojiNode.new(emoji_name) }
|
|
6
|
+
let(:emoji_name) { double }
|
|
7
|
+
let(:emoji) { double }
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
allow(Megingiard::EMOJIS).to receive(:fetch)
|
|
11
|
+
.with(emoji_name)
|
|
12
|
+
.and_return(emoji)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe 'to_s' do
|
|
16
|
+
it 'should be the Emoji from the according Emoji collection' do
|
|
17
|
+
expect(subject.to_s).to eq(emoji)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/hash_wrapper'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::HashWrapper do
|
|
5
|
+
let(:hash) { double }
|
|
6
|
+
let(:item) { double }
|
|
7
|
+
let(:item_name) { double }
|
|
8
|
+
let(:error) { ArgumentError }
|
|
9
|
+
let(:other_error) { double }
|
|
10
|
+
subject { Megingiard::HashWrapper.new(hash, error) }
|
|
11
|
+
|
|
12
|
+
describe 'fetch' do
|
|
13
|
+
it 'should get the according item via fetch' do
|
|
14
|
+
expect(hash).to receive(:fetch)
|
|
15
|
+
.with(item)
|
|
16
|
+
subject.fetch(item)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'should return the fetched item' do
|
|
20
|
+
allow(hash).to receive(:fetch)
|
|
21
|
+
.and_return(item_name)
|
|
22
|
+
expect(subject.fetch(item)).to be item_name
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should raise an error for an unknown item' do
|
|
26
|
+
allow(hash).to receive(:fetch)
|
|
27
|
+
.and_raise(KeyError)
|
|
28
|
+
|
|
29
|
+
expect do
|
|
30
|
+
subject.fetch(item)
|
|
31
|
+
end.to raise_error(error)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/node'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::Node do
|
|
5
|
+
subject { Megingiard::Node.new(first_child, second_child) }
|
|
6
|
+
|
|
7
|
+
let(:first_child) { double(String, to_s: first_child_string) }
|
|
8
|
+
let(:second_child) { double(String, to_s: second_child_string) }
|
|
9
|
+
let(:first_child_string) { double }
|
|
10
|
+
let(:second_child_string) { double }
|
|
11
|
+
let(:concatenation) { double }
|
|
12
|
+
|
|
13
|
+
describe 'to_s' do
|
|
14
|
+
|
|
15
|
+
it 'should concatenate the children as strings' do
|
|
16
|
+
expect(first_child_string).to receive(:+)
|
|
17
|
+
.with(second_child_string)
|
|
18
|
+
|
|
19
|
+
subject.to_s
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'should return the result' do
|
|
23
|
+
allow(first_child_string).to receive(:+)
|
|
24
|
+
.and_return(concatenation)
|
|
25
|
+
|
|
26
|
+
expect(subject.to_s).to eq concatenation
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/text_color_sequence'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::TextColorSequence do
|
|
5
|
+
subject { Megingiard::TextColorSequence }
|
|
6
|
+
let(:color_code) { double }
|
|
7
|
+
let(:name) { double }
|
|
8
|
+
let(:ansi_code) { double }
|
|
9
|
+
|
|
10
|
+
describe 'initialize' do
|
|
11
|
+
it 'should create the ANSI escape sequence with the according code' do
|
|
12
|
+
expect(Megingiard::ANSI_COLORS).to receive(:fetch)
|
|
13
|
+
.with(name)
|
|
14
|
+
.and_return(color_code)
|
|
15
|
+
expect(color_code).to receive(:+)
|
|
16
|
+
.with(30)
|
|
17
|
+
.and_return(ansi_code)
|
|
18
|
+
expect(Megingiard::AnsiEscapeSequence).to receive(:new)
|
|
19
|
+
.with(ansi_code)
|
|
20
|
+
|
|
21
|
+
subject.new(name)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'megingiard/text_color_sequence'
|
|
3
|
+
|
|
4
|
+
describe Megingiard::TextColorSequence do
|
|
5
|
+
subject { Megingiard::TextColorSequence.new(name) }
|
|
6
|
+
let(:color_code) { double(Integer, :+ => ansi_code) }
|
|
7
|
+
let(:name) { double }
|
|
8
|
+
let(:ansi_code) { double }
|
|
9
|
+
let(:ansi_escape_sequence) { double }
|
|
10
|
+
let(:ansi_escape_sequence_as_string) { double }
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
allow(Megingiard::ANSI_COLORS).to receive(:fetch)
|
|
14
|
+
.and_return(color_code)
|
|
15
|
+
allow(Megingiard::AnsiEscapeSequence).to receive(:new)
|
|
16
|
+
.and_return(ansi_escape_sequence)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe 'to_s' do
|
|
20
|
+
it 'should return the String representation of the escape sequence' do
|
|
21
|
+
allow(ansi_escape_sequence).to receive(:to_s)
|
|
22
|
+
.and_return(ansi_escape_sequence_as_string)
|
|
23
|
+
expect(subject.to_s).to eq(ansi_escape_sequence_as_string)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: megingiard
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- moonglum
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-03-31 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: utf8_emoji
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.1.0
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 0.1.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ~>
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 1.6.0
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ~>
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 1.6.0
|
|
41
|
+
description: Tools for creating beautiful CLI output
|
|
42
|
+
email:
|
|
43
|
+
- moonglum@moonbeamlabs.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- .gitignore
|
|
49
|
+
- .rspec
|
|
50
|
+
- .ruby-version
|
|
51
|
+
- .travis.yml
|
|
52
|
+
- Gemfile
|
|
53
|
+
- Gemfile.devtools
|
|
54
|
+
- LICENSE.txt
|
|
55
|
+
- README.md
|
|
56
|
+
- Rakefile
|
|
57
|
+
- config/devtools.yml
|
|
58
|
+
- config/flay.yml
|
|
59
|
+
- config/flog.yml
|
|
60
|
+
- config/mutant.yml
|
|
61
|
+
- config/reek.yml
|
|
62
|
+
- config/rubocop.yml
|
|
63
|
+
- config/yardstick.yml
|
|
64
|
+
- lib/megingiard.rb
|
|
65
|
+
- lib/megingiard/ansi_colors.rb
|
|
66
|
+
- lib/megingiard/ansi_escape_code_validator.rb
|
|
67
|
+
- lib/megingiard/ansi_escape_sequence.rb
|
|
68
|
+
- lib/megingiard/bold_node.rb
|
|
69
|
+
- lib/megingiard/bold_sequence.rb
|
|
70
|
+
- lib/megingiard/centered_canvas.rb
|
|
71
|
+
- lib/megingiard/centered_node.rb
|
|
72
|
+
- lib/megingiard/color_node.rb
|
|
73
|
+
- lib/megingiard/emoji_node.rb
|
|
74
|
+
- lib/megingiard/emojis.rb
|
|
75
|
+
- lib/megingiard/hash_wrapper.rb
|
|
76
|
+
- lib/megingiard/node.rb
|
|
77
|
+
- lib/megingiard/reset_sequence.rb
|
|
78
|
+
- lib/megingiard/terminal_width.rb
|
|
79
|
+
- lib/megingiard/text_color_sequence.rb
|
|
80
|
+
- lib/megingiard/version.rb
|
|
81
|
+
- megingiard.gemspec
|
|
82
|
+
- spec/integration/nodes_spec.rb
|
|
83
|
+
- spec/spec_helper.rb
|
|
84
|
+
- spec/unit/ansi_escape_code_validator/validate_spec.rb
|
|
85
|
+
- spec/unit/ansi_escape_sequence/initialize_spec.rb
|
|
86
|
+
- spec/unit/ansi_escape_sequence/to_s_spec.rb
|
|
87
|
+
- spec/unit/bold_sequence/to_s_spec.rb
|
|
88
|
+
- spec/unit/centered_canvas/draw_centered_row_spec.rb
|
|
89
|
+
- spec/unit/centered_canvas/draw_left_column_spec.rb
|
|
90
|
+
- spec/unit/centered_canvas/draw_right_column_spec.rb
|
|
91
|
+
- spec/unit/centered_canvas/initialize_spec.rb
|
|
92
|
+
- spec/unit/color_node/to_s_spec.rb
|
|
93
|
+
- spec/unit/emoji_node/to_s_spec.rb
|
|
94
|
+
- spec/unit/hash_wrapper/fetch_spec.rb
|
|
95
|
+
- spec/unit/node/to_s_spec.rb
|
|
96
|
+
- spec/unit/text_color_sequence/initialize_spec.rb
|
|
97
|
+
- spec/unit/text_color_sequence/to_s_spec.rb
|
|
98
|
+
homepage: ''
|
|
99
|
+
licenses:
|
|
100
|
+
- MIT
|
|
101
|
+
metadata: {}
|
|
102
|
+
post_install_message:
|
|
103
|
+
rdoc_options: []
|
|
104
|
+
require_paths:
|
|
105
|
+
- lib
|
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - '>='
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
|
+
requirements:
|
|
113
|
+
- - '>='
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: '0'
|
|
116
|
+
requirements: []
|
|
117
|
+
rubyforge_project:
|
|
118
|
+
rubygems_version: 2.2.2
|
|
119
|
+
signing_key:
|
|
120
|
+
specification_version: 4
|
|
121
|
+
summary: This gem provides beautiful output for your CLI
|
|
122
|
+
test_files:
|
|
123
|
+
- spec/integration/nodes_spec.rb
|
|
124
|
+
- spec/spec_helper.rb
|
|
125
|
+
- spec/unit/ansi_escape_code_validator/validate_spec.rb
|
|
126
|
+
- spec/unit/ansi_escape_sequence/initialize_spec.rb
|
|
127
|
+
- spec/unit/ansi_escape_sequence/to_s_spec.rb
|
|
128
|
+
- spec/unit/bold_sequence/to_s_spec.rb
|
|
129
|
+
- spec/unit/centered_canvas/draw_centered_row_spec.rb
|
|
130
|
+
- spec/unit/centered_canvas/draw_left_column_spec.rb
|
|
131
|
+
- spec/unit/centered_canvas/draw_right_column_spec.rb
|
|
132
|
+
- spec/unit/centered_canvas/initialize_spec.rb
|
|
133
|
+
- spec/unit/color_node/to_s_spec.rb
|
|
134
|
+
- spec/unit/emoji_node/to_s_spec.rb
|
|
135
|
+
- spec/unit/hash_wrapper/fetch_spec.rb
|
|
136
|
+
- spec/unit/node/to_s_spec.rb
|
|
137
|
+
- spec/unit/text_color_sequence/initialize_spec.rb
|
|
138
|
+
- spec/unit/text_color_sequence/to_s_spec.rb
|
|
139
|
+
has_rdoc:
|