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.
Files changed (65) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +725 -0
  5. data/Rakefile +9 -0
  6. data/bin/styles +11 -0
  7. data/lib/styles.rb +18 -0
  8. data/lib/styles/application.rb +190 -0
  9. data/lib/styles/colors.rb +289 -0
  10. data/lib/styles/core_ext.rb +12 -0
  11. data/lib/styles/engine.rb +73 -0
  12. data/lib/styles/line.rb +55 -0
  13. data/lib/styles/properties.rb +34 -0
  14. data/lib/styles/properties/background_color.rb +15 -0
  15. data/lib/styles/properties/base.rb +68 -0
  16. data/lib/styles/properties/border.rb +147 -0
  17. data/lib/styles/properties/color.rb +16 -0
  18. data/lib/styles/properties/display.rb +10 -0
  19. data/lib/styles/properties/font_weight.rb +13 -0
  20. data/lib/styles/properties/function.rb +7 -0
  21. data/lib/styles/properties/margin.rb +83 -0
  22. data/lib/styles/properties/match_background_color.rb +28 -0
  23. data/lib/styles/properties/match_color.rb +21 -0
  24. data/lib/styles/properties/match_font_weight.rb +23 -0
  25. data/lib/styles/properties/match_text_decoration.rb +36 -0
  26. data/lib/styles/properties/padding.rb +81 -0
  27. data/lib/styles/properties/text_align.rb +10 -0
  28. data/lib/styles/properties/text_decoration.rb +20 -0
  29. data/lib/styles/properties/width.rb +11 -0
  30. data/lib/styles/rule.rb +67 -0
  31. data/lib/styles/stylesheet.rb +103 -0
  32. data/lib/styles/sub_engines.rb +4 -0
  33. data/lib/styles/sub_engines/base.rb +16 -0
  34. data/lib/styles/sub_engines/color.rb +115 -0
  35. data/lib/styles/sub_engines/layout.rb +158 -0
  36. data/lib/styles/sub_engines/pre_processor.rb +19 -0
  37. data/lib/styles/version.rb +3 -0
  38. data/styles.gemspec +26 -0
  39. data/test/application_test.rb +92 -0
  40. data/test/colors_test.rb +162 -0
  41. data/test/engine_test.rb +59 -0
  42. data/test/integration_test.rb +136 -0
  43. data/test/line_test.rb +24 -0
  44. data/test/properties/background_color_test.rb +36 -0
  45. data/test/properties/base_test.rb +11 -0
  46. data/test/properties/border_test.rb +154 -0
  47. data/test/properties/color_test.rb +28 -0
  48. data/test/properties/display_test.rb +26 -0
  49. data/test/properties/font_weight_test.rb +24 -0
  50. data/test/properties/function_test.rb +28 -0
  51. data/test/properties/margin_test.rb +98 -0
  52. data/test/properties/match_background_color_test.rb +71 -0
  53. data/test/properties/match_color_test.rb +79 -0
  54. data/test/properties/match_font_weight_test.rb +34 -0
  55. data/test/properties/match_text_decoration_test.rb +38 -0
  56. data/test/properties/padding_test.rb +87 -0
  57. data/test/properties/text_align_test.rb +107 -0
  58. data/test/properties/text_decoration_test.rb +25 -0
  59. data/test/properties/width_test.rb +41 -0
  60. data/test/rule_test.rb +39 -0
  61. data/test/stylesheet_test.rb +245 -0
  62. data/test/sub_engines/color_test.rb +144 -0
  63. data/test/sub_engines/layout_test.rb +110 -0
  64. data/test/test_helper.rb +5 -0
  65. metadata +184 -0
@@ -0,0 +1,59 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+ require 'term/ansicolor'
3
+
4
+ class EngineTest < MiniTest::Unit::TestCase
5
+ def test_later_rules_from_same_stylesheet_take_precedence
6
+ hide_all_rule = ':all - { display: none }'
7
+ show_line_rule = "'show' - { display: block }"
8
+
9
+ hide_all_stylesheet = Styles::Stylesheet.from_string("#{show_line_rule}\n#{hide_all_rule}")
10
+
11
+ hide_all_engine = Styles::Engine.new(hide_all_stylesheet)
12
+ assert_equal nil, hide_all_engine.process('show this line')
13
+
14
+ show_a_line_stylesheet = Styles::Stylesheet.from_string("#{hide_all_rule}\n#{show_line_rule}")
15
+
16
+ show_a_line_engine = Styles::Engine.new(show_a_line_stylesheet)
17
+ assert_equal 'show this line', show_a_line_engine.process('show this line')
18
+ end
19
+
20
+ def test_rules_from_later_stylesheets_take_precedence
21
+ hide_all_rule = ':all - { display: none }'
22
+ show_line_rule = "'show' - { display: block }"
23
+
24
+ hide_all_stylesheet = Styles::Stylesheet.from_string(hide_all_rule)
25
+ show_stylesheet = Styles::Stylesheet.from_string(show_line_rule)
26
+
27
+ # First one stylesheet at a time
28
+ assert_equal nil, Styles::Engine.new(hide_all_stylesheet).process('just some text')
29
+ assert_equal 'show this line', Styles::Engine.new(show_stylesheet).process('show this line')
30
+
31
+ # Now use multiple Stylesheets and make sure the Rules of the last one takes precedence
32
+ assert_equal nil, Styles::Engine.new(show_stylesheet, hide_all_stylesheet).process('show this line')
33
+ assert_equal 'show this line', Styles::Engine.new(hide_all_stylesheet, show_stylesheet).process('show this line')
34
+ end
35
+
36
+ def test_rules_can_hide_lines
37
+ stylesheet_text = <<-STYLESHEET
38
+ 'ANNOYING' - {
39
+ display: none
40
+ }
41
+
42
+ /hide this/ - {
43
+ display: none
44
+ }
45
+ STYLESHEET
46
+
47
+ engine = Styles::Engine.new(Styles::Stylesheet.from_string(stylesheet_text))
48
+
49
+ assert_equal 'this is a line', engine.process('this is a line')
50
+ assert_nil engine.process('THIS LINE IS ANNOYING')
51
+ assert_nil engine.process('this line has hide this in it')
52
+ end
53
+
54
+ private
55
+
56
+ def color
57
+ ::Term::ANSIColor
58
+ end
59
+ end
@@ -0,0 +1,136 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+ require 'stringio'
3
+ require 'term/ansicolor'
4
+
5
+ # Tests everything together.
6
+ # Parse stylesheet text, apply those to input, and confirm correct output.
7
+ class IntegrationTest < MiniTest::Unit::TestCase
8
+ def test_rules_can_hide_lines
9
+ @stylesheet = <<-STYLESHEET
10
+ 'ANNOYING' - {
11
+ display: none
12
+ }
13
+
14
+ /hide this/ - {
15
+ display: none
16
+ }
17
+
18
+ :blank - {
19
+ display: none
20
+ }
21
+ STYLESHEET
22
+
23
+ @input = <<-INPUT
24
+ this is a line
25
+ THIS LINE IS ANNOYING
26
+ this line has hide this in it
27
+ this one is also visible
28
+
29
+ the line before this is blank
30
+ INPUT
31
+
32
+ @expected_output = <<-OUTPUT
33
+ this is a line
34
+ this one is also visible
35
+ the line before this is blank
36
+ OUTPUT
37
+
38
+ assert_correct_output
39
+ end
40
+
41
+ def test_various_line_colors_and_styles
42
+ @stylesheet = <<-STYLESHEET
43
+ 'red' - {
44
+ color: red
45
+ }
46
+
47
+ 'fantastic' - {
48
+ color: cyan,
49
+ background_color: yellow
50
+ }
51
+
52
+ /important/ - {
53
+ font_weight: bold
54
+ }
55
+
56
+ /tons/i - {
57
+ color: green,
58
+ background_color: red,
59
+ font_weight: bold,
60
+ text_decoration: underline
61
+ }
62
+ STYLESHEET
63
+
64
+ @input = <<-INPUT
65
+ this line is red
66
+ no color here
67
+ this has fantastic colors
68
+ this line is important
69
+ this has TONS going on
70
+ INPUT
71
+
72
+ @expected_output = <<-OUTPUT
73
+ #{color.red}this line is red#{color.reset}
74
+ no color here
75
+ #{color.cyan}#{color.on_yellow}this has fantastic colors#{color.reset}
76
+ #{color.bold}this line is important#{color.reset}
77
+ #{color.bold}#{color.green}#{color.on_red}#{color.underline}this has TONS going on#{color.reset}
78
+ OUTPUT
79
+
80
+ assert_correct_output
81
+ end
82
+
83
+ def test_various_line_and_match_color_combos
84
+ @stylesheet = <<-STYLESHEET
85
+ 'cyanify' - {
86
+ match_color: cyan
87
+ }
88
+
89
+ /(number) (\\d\\d)/ - {
90
+ match_color: [red, green]
91
+ }
92
+
93
+ 'blue' - {
94
+ color: blue
95
+ }
96
+
97
+ 'on yellow' - {
98
+ background_color: yellow
99
+ }
100
+ STYLESHEET
101
+
102
+ @input = <<-INPUT
103
+ cyanify this
104
+ the number 25 is here
105
+ the number 25 is here, blue otherwise
106
+ the number 25 is here on yellow
107
+ INPUT
108
+
109
+ @expected_output = <<-OUTPUT
110
+ #{color.cyan}cyanify#{color.reset} this
111
+ the #{color.red}number#{color.reset} #{color.green}25#{color.reset} is here
112
+ #{color.blue}the #{color.red}number#{color.blue} #{color.green}25#{color.blue} is here, blue otherwise#{color.reset}
113
+ #{color.on_yellow}the #{color.red}number#{color.reset}#{color.on_yellow} #{color.green}25#{color.reset}#{color.on_yellow} is here on yellow#{color.reset}
114
+ OUTPUT
115
+
116
+ assert_correct_output
117
+ end
118
+
119
+ private
120
+
121
+ def assert_correct_output
122
+ engine = Styles::Engine.new(Styles::Stylesheet.from_string(@stylesheet))
123
+
124
+ output = StringIO.new
125
+ @input.each_line do |line|
126
+ processed_line = engine.process(line)
127
+ output.puts processed_line if processed_line
128
+ end
129
+
130
+ assert_equal @expected_output, output.string
131
+ end
132
+
133
+ def color
134
+ ::Term::ANSIColor
135
+ end
136
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+ require 'term/ansicolor'
3
+
4
+ class LineTest < MiniTest::Unit::TestCase
5
+ include Styles
6
+
7
+ def test_can_update
8
+ original = 'this is a line'
9
+ updated = 'this is an updated line'
10
+ line = Line.new original
11
+ assert_equal original, line.to_s
12
+ assert_equal original, line.text
13
+
14
+ line.text = updated
15
+ assert_equal updated, line.to_s
16
+ assert_equal updated, line.text
17
+ assert_equal original, line.original
18
+
19
+ line = Line.new original
20
+ line.text = updated
21
+ assert_equal updated, line.to_s
22
+ assert_equal original, line.original
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+ require 'term/ansicolor'
3
+
4
+ class BackgroundColorTest < MiniTest::Unit::TestCase
5
+ def test_applies_correct_background_colors_to_lines
6
+ test_line = 'this is a test line, to be background colored'
7
+
8
+ assert_equal "#{color.on_blue}#{test_line}#{color.reset}", process('test', :blue, test_line)
9
+ assert_equal "#{color.on_cyan}#{test_line}#{color.reset}", process('test', :cyan, test_line)
10
+ assert_equal test_line, process('test', :none, test_line)
11
+ end
12
+
13
+ def test_works_with_on_prefixed_colors
14
+ test_line = 'this is a test line, to be background colored'
15
+
16
+ assert_equal "#{color.on_red}#{test_line}#{color.reset}", process('test', :on_red, test_line)
17
+ assert_equal "#{color.on_cyan}#{test_line}#{color.reset}", process('test', :on_cyan, test_line)
18
+ end
19
+
20
+ def test_line_passes_through_with_invalid_color
21
+ test_line = 'this is a test line, to be colored?'
22
+ assert_equal test_line, process('test', :sunshine, test_line)
23
+ end
24
+
25
+ private
26
+
27
+ def process(selector, value, line)
28
+ sub_engine = ::Styles::SubEngines::Color.new
29
+ line = ::Styles::Line.new(line, [::Styles::Properties::BackgroundColor.new(selector, :background_color, value)])
30
+ sub_engine.process(line).to_s
31
+ end
32
+
33
+ def color
34
+ ::Term::ANSIColor
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+ require 'term/ansicolor'
3
+
4
+ class PropertyBaseTest < MiniTest::Unit::TestCase
5
+
6
+ def test_to_sym
7
+ assert_equal :color, ::Styles::Properties::Color.to_sym
8
+ assert_equal :text_align, ::Styles::Properties::TextAlign.to_sym
9
+ end
10
+
11
+ end
@@ -0,0 +1,154 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ class BorderTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ @sub_engine = ::Styles::SubEngines::Layout.new
6
+ end
7
+
8
+ def test_can_use_all_property_names
9
+ [:border, :border_left, :border_right, :border_top, :border_bottom].each do |prop_name|
10
+ assert_equal ::Styles::Properties::Border, ::Styles::Properties.find_class_by_property_name(prop_name)
11
+ end
12
+ end
13
+
14
+ def test_gives_correct_border_values
15
+ bl = prop(:border_left, 'solid green')
16
+ assert_equal :none, bl.top
17
+ assert_equal :none, bl.right
18
+ assert_equal :none, bl.bottom
19
+ assert_equal [:solid, :green], bl.left
20
+ assert_equal [:none, :none, :none, [:solid, :green]], bl.all_border_values
21
+
22
+ assert_equal [[:solid, :default], [:solid, :default], [:solid, :default], [:solid, :default]], prop(:border, :solid).all_border_values
23
+ assert_equal [[:solid, :default], [:solid, :default], [:solid, :default], [:solid, :default]], prop(:border, 'solid').all_border_values
24
+ assert_equal [[:solid, :blue], [:solid, :blue], [:solid, :blue], [:solid, :blue]], prop(:border, 'solid blue').all_border_values
25
+
26
+ assert_equal [:none, :none, :none, :none], prop(:border, :none).all_border_values
27
+ assert_equal [:none, :none, :none, :none], prop(:border_right, :none).all_border_values
28
+ end
29
+
30
+ def test_can_combine_border_properties
31
+ assert_equal [:none, [:dotted, :default], :none, [:solid, :default]],
32
+ combine([prop(:border_left, :solid), prop(:border_right, :dotted)]).all_border_values
33
+ assert_equal [:none, [:dotted, :green], :none, [:solid, :red]],
34
+ combine([prop(:border_left, 'solid red'), prop(:border_right, 'dotted green')]).all_border_values
35
+ assert_equal [[:double, :cyan], [:solid, :white], [:solid, :white], [:solid, :white]],
36
+ combine([prop(:border, 'solid white'), prop(:border_top, 'double cyan')]).all_border_values
37
+ assert_equal [[:double, :cyan], [:dotted, :red], [:solid, :white], [:solid, :white]],
38
+ combine([prop(:border, 'solid white'), prop(:border_top, 'double cyan'), prop(:border_right, 'dotted red')]).all_border_values
39
+ assert_equal [[:solid, :white], [:solid, :white], [:solid, :white], [:solid, :white]],
40
+ combine([prop(:border_top, 'double cyan'), prop(:border, 'solid white')]).all_border_values
41
+ assert_equal [:none, :none, :none, :none],
42
+ combine([prop(:border_top, 'double cyan'), prop(:border, :none)]).all_border_values
43
+ assert_equal [:none, [:solid, :white], [:solid, :white], [:solid, :white]],
44
+ combine([prop(:border, 'solid white'), prop(:border_top, :none)]).all_border_values
45
+ end
46
+
47
+ def test_produces_correct_border_characters
48
+ solid = ::Styles::Properties::Border::SOLID_CHARS
49
+
50
+ solid_prop = prop(:border, :solid)
51
+ assert_equal solid[:top], solid_prop.top_char
52
+ assert_equal solid[:left], solid_prop.left_char
53
+ assert_equal solid[:top_left], solid_prop.top_left_char
54
+ assert_equal solid[:top] * 4, solid_prop.top_char(4)
55
+
56
+ assert_equal "#{solid[:top_left]}#{solid[:top] * 4}#{solid[:top_right]}", solid_prop.top_line_chars(4)
57
+ assert_equal "#{solid[:bottom_left]}#{solid[:bottom] * 4}#{solid[:bottom_right]}", solid_prop.bottom_line_chars(4)
58
+
59
+ solid_green_prop = prop(:border, 'solid green')
60
+ assert_equal "#{color.green}#{solid[:top]}#{color.reset}", solid_green_prop.top_char
61
+ assert_equal "#{color.green}#{solid[:left]}#{color.reset}", solid_green_prop.left_char
62
+ assert_equal "#{color.green}#{solid[:top_left]}#{color.reset}", solid_green_prop.top_left_char
63
+ assert_equal "#{color.green}#{solid[:top] * 4}#{color.reset}", solid_green_prop.top_char(4)
64
+
65
+ assert_equal "#{color.green}#{solid[:top_left]}#{color.reset}#{color.green}#{solid[:top] * 4}" +
66
+ "#{color.reset}#{color.green}#{solid[:top_right]}#{color.reset}", solid_green_prop.top_line_chars(4)
67
+ assert_equal "#{color.green}#{solid[:bottom_left]}#{color.reset}#{color.green}#{solid[:bottom] * 4}" +
68
+ "#{color.reset}#{color.green}#{solid[:bottom_right]}#{color.reset}", solid_green_prop.bottom_line_chars(4)
69
+
70
+ none_prop = prop(:border, :none)
71
+ assert_equal '', none_prop.top_char
72
+ assert_equal '', none_prop.left_char
73
+ assert_equal '', none_prop.top_char(4)
74
+
75
+ none_prop = prop(:border_right, :solid)
76
+ assert_equal '', none_prop.top_char
77
+ assert_equal '', none_prop.left_char
78
+ assert_equal solid[:right], none_prop.right_char
79
+
80
+ bottom_right_prop = combine([prop(:border_bottom, :solid), prop(:border_right, :solid)])
81
+ assert_equal '', bottom_right_prop.top_char
82
+ assert_equal '', bottom_right_prop.left_char
83
+ assert_equal '', bottom_right_prop.top_left_char
84
+ assert_equal '', bottom_right_prop.top_right_char
85
+ assert_equal '', bottom_right_prop.bottom_left_char
86
+ assert_equal solid[:right], bottom_right_prop.right_char
87
+ assert_equal solid[:bottom_right], bottom_right_prop.bottom_right_char
88
+ assert_equal solid[:bottom], bottom_right_prop.bottom_char
89
+ assert_equal "#{solid[:bottom] * 4}#{solid[:bottom_right]}", bottom_right_prop.bottom_line_chars(4)
90
+ end
91
+
92
+ def test_can_apply_a_border
93
+ test_line = 'line for U'
94
+ solid = ::Styles::Properties::Border::SOLID_CHARS
95
+
96
+ solid_border_box = <<SOLID_BORDER
97
+ #{solid[:top_left]}#{solid[:top] * test_line.size}#{solid[:top_right]}
98
+ #{solid[:left]}#{test_line}#{solid[:right]}
99
+ #{solid[:bottom_left]}#{solid[:bottom] * test_line.size}#{solid[:bottom_right]}
100
+ SOLID_BORDER
101
+
102
+ assert_equal solid_border_box, process('line', :border, :solid, test_line)
103
+ end
104
+
105
+ def test_can_apply_a_colored_border
106
+ test_line = 'line for U, with color'
107
+ solid = ::Styles::Properties::Border::SOLID_CHARS
108
+
109
+ solid_blue_border_box = <<SOLID_BORDER
110
+ #{color.blue}#{solid[:top_left]}#{color.reset}#{color.blue}#{solid[:top] * test_line.size}#{color.reset}#{color.blue}#{solid[:top_right]}#{color.reset}
111
+ #{color.blue}#{solid[:left]}#{color.reset}#{test_line}#{color.blue}#{solid[:right]}#{color.reset}
112
+ #{color.blue}#{solid[:bottom_left]}#{color.reset}#{color.blue}#{solid[:bottom] * test_line.size}#{color.reset}#{color.blue}#{solid[:bottom_right]}#{color.reset}
113
+ SOLID_BORDER
114
+
115
+ assert_equal solid_blue_border_box, process('line', :border, 'solid blue', test_line)
116
+ end
117
+
118
+ def test_can_apply_partial_borders
119
+ test_line = 'line for U'
120
+ solid = ::Styles::Properties::Border::SOLID_CHARS
121
+
122
+ partial_border = <<PARTIAL_BORDER
123
+ #{test_line}#{solid[:right]}
124
+ #{solid[:bottom] * test_line.size}#{solid[:bottom_right]}
125
+ PARTIAL_BORDER
126
+
127
+ line = ::Styles::Line.new(test_line, [::Styles::Properties::Border.new([prop(:border_right, :solid), prop(:border_bottom, :solid)])])
128
+ assert_equal partial_border, @sub_engine.process(line).to_s
129
+ end
130
+
131
+ private
132
+
133
+ def process(selector, property_name, value, line)
134
+ line = ::Styles::Line.new(line, [::Styles::Properties::Border.new(selector, property_name, value)])
135
+ result = @sub_engine.process(line)
136
+ result.to_s
137
+ end
138
+
139
+ def prop(name, value, selector='test')
140
+ ::Styles::Properties::Border.new(selector, name, value)
141
+ end
142
+
143
+ def combine(*props)
144
+ ::Styles::Properties::Border.new(props.flatten)
145
+ end
146
+
147
+ def stub_term_width(width)
148
+ @sub_engine.stubs(:terminal_width).returns(width)
149
+ end
150
+
151
+ def color
152
+ ::Term::ANSIColor
153
+ end
154
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+ require 'term/ansicolor'
3
+
4
+ class ColorTest < MiniTest::Unit::TestCase
5
+ def test_applies_correct_colors_to_lines
6
+ test_line = 'this is a test line, to be colored'
7
+
8
+ assert_equal "#{color.red}#{test_line}#{color.reset}", process('test', :red, test_line)
9
+ assert_equal "#{color.blue}#{test_line}#{color.reset}", process('test', :blue, test_line)
10
+ end
11
+
12
+ def test_line_passes_through_with_invalid_color
13
+ test_line = 'this is a test line, to be colored?'
14
+ assert_equal test_line, process('test', :sunshine, test_line)
15
+ end
16
+
17
+ private
18
+
19
+ def process(selector, value, line)
20
+ sub_engine = ::Styles::SubEngines::Color.new
21
+ line = ::Styles::Line.new(line, [::Styles::Properties::Color.new(selector, :color, value)])
22
+ sub_engine.process(line).to_s
23
+ end
24
+
25
+ def color
26
+ ::Term::ANSIColor
27
+ end
28
+ end