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