styles 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.
- data/.gitignore +18 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +725 -0
- data/Rakefile +9 -0
- data/bin/styles +11 -0
- data/lib/styles.rb +18 -0
- data/lib/styles/application.rb +190 -0
- data/lib/styles/colors.rb +289 -0
- data/lib/styles/core_ext.rb +12 -0
- data/lib/styles/engine.rb +73 -0
- data/lib/styles/line.rb +55 -0
- data/lib/styles/properties.rb +34 -0
- data/lib/styles/properties/background_color.rb +15 -0
- data/lib/styles/properties/base.rb +68 -0
- data/lib/styles/properties/border.rb +147 -0
- data/lib/styles/properties/color.rb +16 -0
- data/lib/styles/properties/display.rb +10 -0
- data/lib/styles/properties/font_weight.rb +13 -0
- data/lib/styles/properties/function.rb +7 -0
- data/lib/styles/properties/margin.rb +83 -0
- data/lib/styles/properties/match_background_color.rb +28 -0
- data/lib/styles/properties/match_color.rb +21 -0
- data/lib/styles/properties/match_font_weight.rb +23 -0
- data/lib/styles/properties/match_text_decoration.rb +36 -0
- data/lib/styles/properties/padding.rb +81 -0
- data/lib/styles/properties/text_align.rb +10 -0
- data/lib/styles/properties/text_decoration.rb +20 -0
- data/lib/styles/properties/width.rb +11 -0
- data/lib/styles/rule.rb +67 -0
- data/lib/styles/stylesheet.rb +103 -0
- data/lib/styles/sub_engines.rb +4 -0
- data/lib/styles/sub_engines/base.rb +16 -0
- data/lib/styles/sub_engines/color.rb +115 -0
- data/lib/styles/sub_engines/layout.rb +158 -0
- data/lib/styles/sub_engines/pre_processor.rb +19 -0
- data/lib/styles/version.rb +3 -0
- data/styles.gemspec +26 -0
- data/test/application_test.rb +92 -0
- data/test/colors_test.rb +162 -0
- data/test/engine_test.rb +59 -0
- data/test/integration_test.rb +136 -0
- data/test/line_test.rb +24 -0
- data/test/properties/background_color_test.rb +36 -0
- data/test/properties/base_test.rb +11 -0
- data/test/properties/border_test.rb +154 -0
- data/test/properties/color_test.rb +28 -0
- data/test/properties/display_test.rb +26 -0
- data/test/properties/font_weight_test.rb +24 -0
- data/test/properties/function_test.rb +28 -0
- data/test/properties/margin_test.rb +98 -0
- data/test/properties/match_background_color_test.rb +71 -0
- data/test/properties/match_color_test.rb +79 -0
- data/test/properties/match_font_weight_test.rb +34 -0
- data/test/properties/match_text_decoration_test.rb +38 -0
- data/test/properties/padding_test.rb +87 -0
- data/test/properties/text_align_test.rb +107 -0
- data/test/properties/text_decoration_test.rb +25 -0
- data/test/properties/width_test.rb +41 -0
- data/test/rule_test.rb +39 -0
- data/test/stylesheet_test.rb +245 -0
- data/test/sub_engines/color_test.rb +144 -0
- data/test/sub_engines/layout_test.rb +110 -0
- data/test/test_helper.rb +5 -0
- metadata +184 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
module Styles
|
2
|
+
module SubEngines
|
3
|
+
class Base
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def extract_sub_engine_properties(properties)
|
8
|
+
properties.select { |prop| prop.class.sub_engines.include? self.class }
|
9
|
+
end
|
10
|
+
|
11
|
+
def colors
|
12
|
+
::Styles::Colors
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Styles
|
2
|
+
module SubEngines
|
3
|
+
class Color < Base
|
4
|
+
|
5
|
+
def process(line)
|
6
|
+
color_sub_engine_properties = extract_sub_engine_properties line.applicable_properties
|
7
|
+
line_properties, match_properties = color_sub_engine_properties.partition do |p|
|
8
|
+
property_type(p) == :line
|
9
|
+
end
|
10
|
+
|
11
|
+
line_colors = get_line_colors(line_properties)
|
12
|
+
|
13
|
+
colored_line = line.to_s.chomp
|
14
|
+
|
15
|
+
match_properties.each do |prop|
|
16
|
+
next unless prop.valid_value?
|
17
|
+
if prop.selector.is_a? String
|
18
|
+
colored_line = apply_string_match_property(prop, line_colors, colored_line)
|
19
|
+
elsif prop.selector.is_a? Regexp
|
20
|
+
colored_line = apply_regex_match_property(prop, line_colors, colored_line)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
line.text = line_colors.any? ? "#{colors[line_colors]}#{colored_line}#{colors[:reset]}" : colored_line
|
25
|
+
line
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Get the property type (:line or :match) of a property instance
|
31
|
+
def property_type(property)
|
32
|
+
klass = property.class
|
33
|
+
if klass.constants.include?(:COLOR_PROPERTY_TYPE) && klass::COLOR_PROPERTY_TYPE == :match
|
34
|
+
:match
|
35
|
+
else
|
36
|
+
:line
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_line_colors(line_properties)
|
41
|
+
line_properties.map(&:color_to_use).reject { |c| !colors.valid?(c) }.sort
|
42
|
+
end
|
43
|
+
|
44
|
+
# Apply a match property that has a String selector to the given line. Takes into account
|
45
|
+
# line property colors and makes sure the rest of the line has those applied to it.
|
46
|
+
def apply_string_match_property(property, line_colors, line)
|
47
|
+
before_match_colors, after_match_colors = colors.line_substring_color_transitions(
|
48
|
+
line_colors, property.color_to_use
|
49
|
+
)
|
50
|
+
line.gsub(property.selector, "#{before_match_colors}\\0#{after_match_colors}")
|
51
|
+
end
|
52
|
+
|
53
|
+
def apply_regex_match_property(property, line_colors, line)
|
54
|
+
selector, value = property.selector, property.value
|
55
|
+
if value.is_a? Array
|
56
|
+
return line unless selector.is_a?(Regexp)
|
57
|
+
apply_colors_to_multiple_matches(property, line_colors, line)
|
58
|
+
elsif value.is_a? Symbol
|
59
|
+
before_match_colors, after_match_colors = colors.line_substring_color_transitions(
|
60
|
+
line_colors, property.color_to_use
|
61
|
+
)
|
62
|
+
line.gsub(selector) { |match| "#{before_match_colors}#{match}#{after_match_colors}" }
|
63
|
+
else
|
64
|
+
line
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Use the Regexp selector to determine match groups on the given line. Then apply the array
|
69
|
+
# of colors to the each match group, first color to first group and so on. Ignore the last
|
70
|
+
# match groups if they do not have corresponding colors and vice versa.
|
71
|
+
#
|
72
|
+
# If there are color that should be applied to the entire line then make sure to turn them
|
73
|
+
# off before applying match colors and back on after the match.
|
74
|
+
def apply_colors_to_multiple_matches(property, line_colors, line)
|
75
|
+
selector, match_colors = property.selector, [property.color_to_use].flatten
|
76
|
+
match_data = selector.match(line)
|
77
|
+
return line unless match_data && (match_data.size > 1)
|
78
|
+
colored_line = line.dup
|
79
|
+
|
80
|
+
offsets = (1...(match_data.size)).to_a.map { |idx| match_data.offset(idx) }
|
81
|
+
|
82
|
+
# Work backward through the matches because working forward would throw off indicies.
|
83
|
+
# Determine the original index of the match and apply the corresponding color. If we
|
84
|
+
# do not have enough colors for the last match(es) then skip them.
|
85
|
+
# TODO: clean this up, it just feels hacky
|
86
|
+
offsets.reverse.each_with_index do |offset, index|
|
87
|
+
orig_match_index = offsets.size - index - 1
|
88
|
+
match_color = match_colors[orig_match_index]
|
89
|
+
next unless match_color
|
90
|
+
|
91
|
+
before_match_colors, after_match_colors = colors.line_substring_color_transitions(
|
92
|
+
line_colors, match_color
|
93
|
+
)
|
94
|
+
|
95
|
+
beg_idx, end_idx = offset
|
96
|
+
colored_line.insert(end_idx, after_match_colors)
|
97
|
+
colored_line.insert(beg_idx, before_match_colors)
|
98
|
+
end
|
99
|
+
|
100
|
+
colored_line
|
101
|
+
end
|
102
|
+
|
103
|
+
module PropertyMixin
|
104
|
+
# Can be overridden if the color to use should be derived differently
|
105
|
+
def color_to_use
|
106
|
+
value
|
107
|
+
end
|
108
|
+
|
109
|
+
def valid_value?
|
110
|
+
self.class::VALUES.include?(value)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Styles
|
4
|
+
module SubEngines
|
5
|
+
class Layout < Base
|
6
|
+
|
7
|
+
def process(line)
|
8
|
+
layout_sub_engine_properties = extract_sub_engine_properties line.applicable_properties
|
9
|
+
|
10
|
+
if should_hide?(line)
|
11
|
+
line.text = nil
|
12
|
+
return line
|
13
|
+
end
|
14
|
+
|
15
|
+
apply_width_and_text_align(line)
|
16
|
+
apply_padding_border_margin(line)
|
17
|
+
|
18
|
+
line
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def should_hide?(line)
|
24
|
+
display_property = line.applicable_properties.find { |prop| prop.class == ::Styles::Properties::Display }
|
25
|
+
display_property && ::Styles::Properties::Display::HIDE_VALUES.include?(display_property.value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def apply_width_and_text_align(line)
|
29
|
+
width_prop, text_align_prop = line.prop(:width), line.prop(:text_align)
|
30
|
+
size_no_color = colors.uncolor(line.text).size
|
31
|
+
width = width_prop ? width_prop.width : terminal_width
|
32
|
+
|
33
|
+
return if size_no_color >= width
|
34
|
+
diff = width - size_no_color
|
35
|
+
|
36
|
+
bg_color = if bg_color_prop = line.prop(:background_color)
|
37
|
+
bg_color_prop.color_to_use
|
38
|
+
else
|
39
|
+
:none
|
40
|
+
end
|
41
|
+
|
42
|
+
if text_align_prop
|
43
|
+
case text_align_prop.value
|
44
|
+
when :left
|
45
|
+
# Pad right only if width explicitly set
|
46
|
+
line.text = "#{line.text}#{colors.color(' ' * diff, bg_color)}" if width_prop
|
47
|
+
when :right
|
48
|
+
pad = ' ' * diff
|
49
|
+
pad = colors.color(pad, bg_color) if width_prop
|
50
|
+
line.text = "#{pad}#{line.text}"
|
51
|
+
when :center
|
52
|
+
before, after = (' ' * (diff/2)), (' ' * (diff/2 + diff%2))
|
53
|
+
before, after = [before, after].map { |pad| colors.color(pad, bg_color)} if width_prop
|
54
|
+
line.text = "#{before}#{line.text}#{after}"
|
55
|
+
end
|
56
|
+
else
|
57
|
+
# Assume left align, pad right only if width explicitly set
|
58
|
+
line.text = "#{line.text}#{colors.color(' ' * diff, bg_color)}" if width_prop
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def apply_padding_border_margin(line)
|
63
|
+
padding, margin = (line.prop(:padding) || blank_space_property), (line.prop(:margin) || blank_space_property)
|
64
|
+
border = line.prop(:border) || ::Styles::Properties::Border.new(:any, :border, :none)
|
65
|
+
|
66
|
+
return unless padding || margin || border
|
67
|
+
|
68
|
+
bg_color = if bg_color_prop = line.prop(:background_color)
|
69
|
+
bg_color_prop.valid_value? ? bg_color_prop.color_to_use : :none
|
70
|
+
else
|
71
|
+
:none
|
72
|
+
end
|
73
|
+
|
74
|
+
# First establish the main line padding and border
|
75
|
+
line.left = colors.force_color("#{border.left_char}#{' ' * padding.left}", bg_color)
|
76
|
+
line.right = colors.force_color("#{' ' * padding.right}#{border.right_char}", bg_color)
|
77
|
+
|
78
|
+
# Calculate margins and add to the main line
|
79
|
+
margin_left, margin_right =
|
80
|
+
if margin.left == :auto || margin.right == :auto
|
81
|
+
diff = terminal_width - line.total_width
|
82
|
+
if diff > 0
|
83
|
+
[(' ' * (diff/2)), (' ' * (diff/2 + diff%2))]
|
84
|
+
else
|
85
|
+
['', '']
|
86
|
+
end
|
87
|
+
else
|
88
|
+
[' ' * margin.left, ' ' * margin.right]
|
89
|
+
end
|
90
|
+
|
91
|
+
line.left = margin_left + line.left
|
92
|
+
line.right = line.right + margin_right
|
93
|
+
|
94
|
+
content_width = line.content_width
|
95
|
+
border_width = padding.left + content_width + padding.right
|
96
|
+
|
97
|
+
margin_line = "#{' ' * line.total_width}\n"
|
98
|
+
padding_line = "#{margin_left}#{colors.color(' ' * border_width, bg_color)}#{margin_right}\n"
|
99
|
+
|
100
|
+
line.top = margin_line * margin.top if margin.top.is_a?(Integer)
|
101
|
+
|
102
|
+
extender_line = margin_left +
|
103
|
+
colors.force_color("#{border.left_char}#{' ' * border_width}#{border.right_char}", bg_color) +
|
104
|
+
margin_right + "\n"
|
105
|
+
|
106
|
+
if border.top == :none
|
107
|
+
line.top << padding_line * padding.top
|
108
|
+
else
|
109
|
+
line.top << margin_left +
|
110
|
+
colors.force_color("#{border.top_line_chars(border_width)}", bg_color) +
|
111
|
+
margin_right + "\n"
|
112
|
+
line.top << (extender_line * padding.top) if padding.top > 0
|
113
|
+
end
|
114
|
+
|
115
|
+
if border.bottom == :none
|
116
|
+
line.bottom = padding_line * padding.bottom
|
117
|
+
else
|
118
|
+
line.bottom = ''
|
119
|
+
line.bottom << (extender_line * padding.bottom) if padding.bottom > 0
|
120
|
+
line.bottom << margin_left +
|
121
|
+
colors.force_color("#{border.bottom_line_chars(border_width)}", bg_color) +
|
122
|
+
margin_right + "\n"
|
123
|
+
end
|
124
|
+
|
125
|
+
line.bottom << margin_line * margin.bottom if margin.bottom.is_a?(Integer)
|
126
|
+
end
|
127
|
+
|
128
|
+
def apply_margin(line)
|
129
|
+
margin = line.prop(:margin)
|
130
|
+
return unless margin
|
131
|
+
|
132
|
+
if margin.left > 0
|
133
|
+
line.left = ' ' * margin.left
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Tries to determine terminal width, returns 80 by default
|
138
|
+
def terminal_width
|
139
|
+
require 'io/console'
|
140
|
+
IO.console.winsize[1]
|
141
|
+
rescue LoadError
|
142
|
+
begin
|
143
|
+
`tput co`.to_i
|
144
|
+
rescue
|
145
|
+
80
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def blank_space_property
|
150
|
+
OpenStruct.new(top: 0, right: 0, bottom: 0, left: 0)
|
151
|
+
end
|
152
|
+
|
153
|
+
def blank_border_property
|
154
|
+
OpenStruct.new(top: :none, right: :none, bottom: :none, left: :none)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Styles
|
2
|
+
module SubEngines
|
3
|
+
class PreProcessor < Base
|
4
|
+
def process(line)
|
5
|
+
apply_function(line)
|
6
|
+
|
7
|
+
line
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def apply_function(line)
|
13
|
+
if (fn = line.prop(:function)) && fn.value.respond_to?(:call)
|
14
|
+
line.text = fn.value.call(line.text)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/styles.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'styles/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'styles'
|
8
|
+
gem.version = Styles::VERSION
|
9
|
+
gem.authors = ['Aaron Royer']
|
10
|
+
gem.email = ['aaronroyer@gmail.com']
|
11
|
+
gem.description = %q{plain text stylesheets}
|
12
|
+
gem.summary = %q{A utility for processing text that provides a Ruby DSL leveraging CSS concepts}
|
13
|
+
gem.homepage = 'http://github.com/aaronroyer/styles'
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.required_ruby_version = '>= 1.9.0'
|
21
|
+
|
22
|
+
gem.add_dependency 'term-ansicolor', '>= 1.1.0'
|
23
|
+
|
24
|
+
gem.add_development_dependency 'timecop'
|
25
|
+
gem.add_development_dependency 'mocha'
|
26
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
require 'term/ansicolor'
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'stringio'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'timecop'
|
7
|
+
|
8
|
+
class ApplicationTest < MiniTest::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
ENV['STYLES_DIR'] = @stylesheets_dir = Dir.mktmpdir
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
FileUtils.remove_entry_secure(@stylesheets_dir) if File.directory?(@stylesheets_dir)
|
15
|
+
ENV['STYLES_DIR'] = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_run_with_default_stylesheet
|
19
|
+
File.open(File.join(stylesheets_dir, 'default.rb'), 'w') do |f|
|
20
|
+
f.write " 'hide' - { display: none } "
|
21
|
+
end
|
22
|
+
|
23
|
+
input = StringIO.new "hide this\nnot this\n", 'r'
|
24
|
+
output = StringIO.new
|
25
|
+
|
26
|
+
app = ::Styles::Application.new input_stream: input, output_stream: output
|
27
|
+
app.send :read_stylesheets
|
28
|
+
app.send :process
|
29
|
+
|
30
|
+
assert_equal "not this\n", output.string
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_auto_reload_updated_stylesheet
|
34
|
+
default_stylesheet = File.join stylesheets_dir, 'default.rb'
|
35
|
+
File.open(default_stylesheet, 'w') { |f| f.write " 'word' - { color: green } " }
|
36
|
+
|
37
|
+
input = StringIO.new "has a word\nhas a word\n", 'r'
|
38
|
+
output = StringIO.new
|
39
|
+
app = ::Styles::Application.new input_stream: input, output_stream: output
|
40
|
+
|
41
|
+
app.send :read_stylesheets
|
42
|
+
app.send :process_next_line
|
43
|
+
assert_equal "#{color.green}has a word#{color.reset}\n", output.string
|
44
|
+
|
45
|
+
orig_time = Time.now
|
46
|
+
|
47
|
+
output.truncate(output.rewind)
|
48
|
+
|
49
|
+
File.open(default_stylesheet, 'w') { |f| f.write " 'word' - { color: red } " }
|
50
|
+
FileUtils.touch(default_stylesheet, mtime: orig_time + 2)
|
51
|
+
|
52
|
+
Timecop.freeze(orig_time + 4) do
|
53
|
+
app.send :process_next_line
|
54
|
+
end
|
55
|
+
assert_equal "#{color.red}has a word#{color.reset}\n", output.string
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_does_not_auto_reload_updated_stylesheet_inside_check_interval
|
59
|
+
interval = ::Styles::Application::STYLESHEET_CHECK_INTERVAL_SECONDS
|
60
|
+
|
61
|
+
default_stylesheet = File.join stylesheets_dir, 'default.rb'
|
62
|
+
File.open(default_stylesheet, 'w') { |f| f.write " 'word' - { color: green } " }
|
63
|
+
|
64
|
+
input = StringIO.new "has a word\nhas a word\n", 'r'
|
65
|
+
output = StringIO.new
|
66
|
+
app = ::Styles::Application.new input_stream: input, output_stream: output
|
67
|
+
|
68
|
+
app.send :read_stylesheets
|
69
|
+
app.send :process_next_line
|
70
|
+
assert_equal "#{color.green}has a word#{color.reset}\n", output.string
|
71
|
+
|
72
|
+
orig_time = Time.now
|
73
|
+
|
74
|
+
output.truncate(output.rewind)
|
75
|
+
|
76
|
+
File.open(default_stylesheet, 'w') { |f| f.write " 'word' - { color: red } " }
|
77
|
+
FileUtils.touch(default_stylesheet, mtime: orig_time + (interval - 1))
|
78
|
+
|
79
|
+
Timecop.freeze(orig_time + (interval - 1)) do
|
80
|
+
app.send :process_next_line
|
81
|
+
end
|
82
|
+
assert_equal "#{color.green}has a word#{color.reset}\n", output.string
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
attr_reader :stylesheets_dir
|
88
|
+
|
89
|
+
def color
|
90
|
+
::Term::ANSIColor
|
91
|
+
end
|
92
|
+
end
|
data/test/colors_test.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
require 'term/ansicolor'
|
3
|
+
|
4
|
+
class ColorsTest < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def test_can_access_basic_colors_with_brackets
|
7
|
+
assert_equal ansi.red, c[:red]
|
8
|
+
assert_equal ansi.blue, c[:blue]
|
9
|
+
assert_equal ansi.on_cyan, c[:on_cyan]
|
10
|
+
|
11
|
+
assert_nil c[:bogus]
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_can_access_compound_colors_with_brackets
|
15
|
+
assert_equal ansi.on_white + ansi.red , c[:red_on_white]
|
16
|
+
assert_equal ansi.blue + ansi.on_blue, c[:blue_on_blue]
|
17
|
+
|
18
|
+
assert_nil c[:red_on_bogus]
|
19
|
+
assert_nil c[:bogus_on_bogus]
|
20
|
+
assert_nil c[:bogus_on_red]
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_can_access_multiple_colors_with_brackets
|
24
|
+
assert_equal ansi.red + ansi.white, c[:red, :white]
|
25
|
+
assert_equal ansi.blue + ansi.red + ansi.white, c[:red, :white, :blue]
|
26
|
+
assert_equal ansi.on_blue + ansi.red + ansi.white, c[:red, :white_on_blue]
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_can_use_arrays_of_colors_with_brackets
|
30
|
+
assert_equal ansi.red + ansi.white, c[[:red, :white]]
|
31
|
+
assert_equal ansi.blue + ansi.red + ansi.white, c[[:red, :white, :blue]]
|
32
|
+
assert_equal ansi.on_blue + ansi.red + ansi.white, c[[:red, :white_on_blue]]
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_maps_certain_css_values_to_ansi
|
36
|
+
assert_equal ansi.strikethrough, c[:line_through]
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_basic_colors_are_valid
|
40
|
+
assert c.valid?(:red)
|
41
|
+
assert c.valid?(:on_red)
|
42
|
+
assert c.valid?(:green)
|
43
|
+
assert c.valid?(:on_green)
|
44
|
+
assert c.valid?(:magenta)
|
45
|
+
assert c.valid?(:on_magenta)
|
46
|
+
|
47
|
+
assert !c.valid?(:bogus)
|
48
|
+
assert !c.valid?(:on_bogus)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_compound_colors_are_valid
|
52
|
+
assert c.valid?(:red_on_white)
|
53
|
+
assert c.valid?(:blue_on_blue)
|
54
|
+
assert c.valid?(:black_on_blue)
|
55
|
+
|
56
|
+
assert !c.valid?(:blue_on_bogus)
|
57
|
+
assert !c.valid?(:bogus_on_blue)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_various_other_ansi_escape_codes_are_valid
|
61
|
+
assert c.valid?(:bold)
|
62
|
+
assert c.valid?(:line_through), 'Mapped values are also valid'
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_hard_color_transitions
|
66
|
+
assert_equal ansi.red, c.color_transition([:blue], [:red])
|
67
|
+
assert_equal ansi.red, c.color_transition(:blue, :red)
|
68
|
+
assert_equal ansi.reset + ansi.red, c.color_transition(:on_blue, :red)
|
69
|
+
assert_equal ansi.red + ansi.on_white, c.color_transition([:green, :on_blue], [:red, :on_white])
|
70
|
+
assert_equal ansi.reset + ansi.underline, c.color_transition(:blue, :underline)
|
71
|
+
assert_equal ansi.reset + ansi.blue, c.color_transition(:underline, :blue)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_soft_color_transitions
|
75
|
+
assert_equal ansi.red, c.color_transition([:blue], [:red], false)
|
76
|
+
assert_equal ansi.red, c.color_transition([:on_blue], [:red], false)
|
77
|
+
assert_equal ansi.on_red, c.color_transition([:blue], [:on_red], false)
|
78
|
+
assert_equal ansi.red, c.color_transition([:green, :on_blue], [:red], false)
|
79
|
+
assert_equal ansi.underline, c.color_transition(:blue, :underline, false)
|
80
|
+
assert_equal ansi.blue, c.color_transition(:underline, :blue, false)
|
81
|
+
|
82
|
+
assert_equal ansi.red, c.color_transition([:blue], [:red], false)
|
83
|
+
assert_equal '', c.color_transition([:blue], [:blue], false)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_color_transitions_blank_when_not_necessary
|
87
|
+
assert_equal '', c.color_transition([:blue], [:blue])
|
88
|
+
assert_equal '', c.color_transition([:on_white], [:on_white])
|
89
|
+
assert_equal '', c.color_transition([:underline], [:underline])
|
90
|
+
assert_equal '', c.color_transition([:blue, :on_white], [:blue, :on_white])
|
91
|
+
assert_equal '', c.color_transition([:blue, :on_white, :underline], [:blue, :on_white, :underline])
|
92
|
+
assert_equal '', c.color_transition([:blue, :on_white], [:on_white, :blue])
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_color_transition_with_negations
|
96
|
+
assert_equal ansi.reset, c.color_transition(:blue, :no_fg_color)
|
97
|
+
assert_equal ansi.reset, c.color_transition(:on_blue, :no_bg_color)
|
98
|
+
assert_equal ansi.reset, c.color_transition(:blue, :no_bg_color)
|
99
|
+
|
100
|
+
assert_equal ansi.reset, c.color_transition([:blue, :on_white], :no_bg_color)
|
101
|
+
assert_equal ansi.reset + ansi.red, c.color_transition([:blue, :on_white], [:red, :no_bg_color])
|
102
|
+
assert_equal ansi.reset + ansi.blue, c.color_transition([:blue, :on_white], [:blue, :no_bg_color])
|
103
|
+
|
104
|
+
assert_equal ansi.reset + ansi.red, c.color_transition([:blue, :on_white], [:red, :no_bg_color])
|
105
|
+
assert_equal ansi.reset + ansi.blue, c.color_transition([:blue, :on_white], [:blue, :no_bg_color])
|
106
|
+
|
107
|
+
assert_equal ansi.blue, c.color_transition(:no_fg_color, :blue)
|
108
|
+
assert_equal ansi.on_red, c.color_transition(:no_bg_color, :on_red)
|
109
|
+
assert_equal '', c.color_transition([:blue, :no_bg_color], :blue)
|
110
|
+
assert_equal ansi.on_blue, c.color_transition(:no_fg_color, :on_blue)
|
111
|
+
assert_equal '', c.color_transition([:no_fg_color, :on_blue], :on_blue)
|
112
|
+
|
113
|
+
|
114
|
+
assert_equal ansi.reset, c.color_transition(:blue, :no_fg_color, false)
|
115
|
+
assert_equal ansi.reset, c.color_transition(:on_blue, :no_bg_color, false)
|
116
|
+
assert_equal '', c.color_transition(:blue, :no_bg_color, false)
|
117
|
+
|
118
|
+
assert_equal ansi.reset + ansi.blue, c.color_transition([:blue, :on_white], :no_bg_color, false)
|
119
|
+
assert_equal ansi.reset + ansi.red, c.color_transition([:blue, :on_white], [:red, :no_bg_color], false)
|
120
|
+
assert_equal ansi.reset + ansi.blue, c.color_transition([:blue, :on_white], [:blue, :no_bg_color], false)
|
121
|
+
|
122
|
+
assert_equal ansi.reset + ansi.red, c.color_transition([:blue, :on_white], [:red, :no_bg_color], false)
|
123
|
+
assert_equal ansi.reset + ansi.blue, c.color_transition([:blue, :on_white], [:blue, :no_bg_color], false)
|
124
|
+
|
125
|
+
assert_equal ansi.blue, c.color_transition(:no_fg_color, :blue, false)
|
126
|
+
assert_equal ansi.on_red, c.color_transition(:no_bg_color, :on_red, false)
|
127
|
+
assert_equal '', c.color_transition([:blue, :no_bg_color], :blue, false)
|
128
|
+
assert_equal ansi.on_blue, c.color_transition(:no_fg_color, :on_blue, false)
|
129
|
+
assert_equal '', c.color_transition([:no_fg_color, :on_blue], :on_blue, false)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_can_color_strings_with_auto_reset
|
133
|
+
assert_equal ansi.blue + 'hello' + ansi.reset, c.color('hello', :blue)
|
134
|
+
assert_equal ansi.blue + ansi.on_green + 'hello' + ansi.reset, c.color('hello', :blue, :on_green)
|
135
|
+
assert_equal ansi.blue + ansi.on_green + 'hello' + ansi.reset, c.color('hello', [:blue, :on_green])
|
136
|
+
assert_equal ansi.underline + 'hello' + ansi.reset, c.color('hello', :underline)
|
137
|
+
assert_equal 'hello', c.color('hello', :invalid)
|
138
|
+
assert_equal 'hello', c.color('hello', :none)
|
139
|
+
assert_equal ansi.red + 'hello' + ansi.reset, c.color('hello', :none, :red)
|
140
|
+
assert_equal '', c.color('', :red)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_force_color
|
144
|
+
str = "has #{ansi.red}some#{ansi.reset} red"
|
145
|
+
assert_equal "#{ansi.on_blue}has #{ansi.red}some#{ansi.reset}#{ansi.on_blue} red#{ansi.reset}",
|
146
|
+
c.force_color(str, :on_blue)
|
147
|
+
|
148
|
+
assert_equal ansi.blue + 'hello' + ansi.reset, c.force_color('hello', :blue)
|
149
|
+
assert_equal '', c.force_color('', :red)
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def c
|
155
|
+
::Styles::Colors
|
156
|
+
end
|
157
|
+
|
158
|
+
def ansi
|
159
|
+
::Term::ANSIColor
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|