styles 0.0.1

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