intranet-core 1.0.0

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 (37) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +38 -0
  3. data/lib/core_extensions.rb +12 -0
  4. data/lib/core_extensions/string.rb +43 -0
  5. data/lib/core_extensions/tree.rb +84 -0
  6. data/lib/core_extensions/webrick/httpresponse.rb +22 -0
  7. data/lib/intranet/abstract_responder.rb +34 -0
  8. data/lib/intranet/core.rb +125 -0
  9. data/lib/intranet/core/builder.rb +98 -0
  10. data/lib/intranet/core/haml_wrapper.rb +60 -0
  11. data/lib/intranet/core/locales.rb +47 -0
  12. data/lib/intranet/core/servlet.rb +42 -0
  13. data/lib/intranet/core/version.rb +8 -0
  14. data/lib/intranet/logger.rb +38 -0
  15. data/lib/intranet/resources/haml/http_error.haml +27 -0
  16. data/lib/intranet/resources/haml/skeleton.haml +52 -0
  17. data/lib/intranet/resources/haml/title_and_breadcrumb.haml +8 -0
  18. data/lib/intranet/resources/locales/en.yml +46 -0
  19. data/lib/intranet/resources/locales/fr.yml +46 -0
  20. data/lib/intranet/resources/www/background.jpg +0 -0
  21. data/lib/intranet/resources/www/error.png +0 -0
  22. data/lib/intranet/resources/www/favicon.ico +0 -0
  23. data/lib/intranet/resources/www/fonts/SourceSansPro.woff2 +0 -0
  24. data/lib/intranet/resources/www/nav.js +25 -0
  25. data/lib/intranet/resources/www/style.css +306 -0
  26. data/spec/core_extensions/string_spec.rb +135 -0
  27. data/spec/core_extensions/tree_spec.rb +208 -0
  28. data/spec/core_extensions/webrick/httpresponse_spec.rb +43 -0
  29. data/spec/intranet/core/fr.yml +5 -0
  30. data/spec/intranet/core/haml_wrapper_spec.rb +70 -0
  31. data/spec/intranet/core/locales_spec.rb +74 -0
  32. data/spec/intranet/core_spec.rb +403 -0
  33. data/spec/intranet/logger_spec.rb +129 -0
  34. data/spec/spec_helper.rb +50 -0
  35. data/spec/test_responder/responder.rb +42 -0
  36. data/spec/test_responder/www/style.css +5 -0
  37. metadata +218 -0
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'core_extensions/string'
4
+
5
+ RSpec.describe CoreExtensions::String do
6
+ before do
7
+ String.include described_class
8
+ end
9
+
10
+ describe '#unaccentize' do
11
+ context 'given an empty string' do
12
+ it 'should return an empty string' do
13
+ tested_string = ''
14
+ expect(tested_string.unaccentize).to eql(tested_string)
15
+ end
16
+ end
17
+
18
+ context 'given the printable ASCII characters (0x20 to 0x7E)' do
19
+ it 'should not modify them' do
20
+ tested_string1 = ' !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO'
21
+ tested_string2 = 'PQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
22
+ expect(tested_string1.unaccentize).to eql(tested_string1)
23
+ expect(tested_string2.unaccentize).to eql(tested_string2)
24
+ end
25
+ end
26
+
27
+ context 'given the Unicode characters from the Latin-1 supplement (0xA0 to 0xFF)' do
28
+ it 'should replace the accented characters with their unaccented version' do
29
+ tested_string1 = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐ'
30
+ tested_string2 = 'ÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
31
+ expected_string1 = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿AAAAAAAECEEEEIIIID'
32
+ expected_string2 = 'NOOOOO×OUUUUYÞssaaaaaaaeceeeeiiiidnooooo÷ouuuuyþy'
33
+ expect(tested_string1.unaccentize).to eql(expected_string1)
34
+ expect(tested_string2.unaccentize).to eql(expected_string2)
35
+ end
36
+ end
37
+
38
+ context 'given the Unicode characters from the Latin Extended-A (0x100 to 0x17F)' do
39
+ it 'should replace the accented characters with their unaccented version' do
40
+ tested_string1 = 'ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿ'
41
+ tested_string2 = 'ŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ'
42
+ expected_string1 = 'AaAaAaCcCcCcCcDdDdEeEeEeEeEeGgGgGgGgHhHhIiIiIiIiIiIJijJjKkkLlLlLlL'
43
+ expected_string2 = 'lLlNnNnNnnNnOoOoOoOEoeRrRrRrSsSsSsSsTtTtTtUuUuUuUuUuUuWwYyYZzZzZzs'
44
+ expect(tested_string1.unaccentize).to eql(expected_string1)
45
+ expect(tested_string2.unaccentize).to eql(expected_string2)
46
+ end
47
+ end
48
+ end
49
+
50
+ describe '#urlize' do
51
+ context 'given an empty string' do
52
+ it 'should return an empty string' do
53
+ tested_string = ''
54
+ expect(tested_string.urlize).to eql(tested_string)
55
+ end
56
+ end
57
+
58
+ context 'given an uppercase string' do
59
+ it 'should return the corresponding downcased string' do
60
+ tested_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
61
+ expected_string = 'abcdefghijklmnopqrstuvwxyz'
62
+ expect(tested_string.urlize).to eql(expected_string)
63
+ end
64
+ end
65
+
66
+ context 'given a string with leading and trailing spaces' do
67
+ it 'should return the same string with leading and trailing spaces removed' do
68
+ tested_string = ' abcde '
69
+ expected_string = 'abcde'
70
+ expect(tested_string.urlize).to eql(expected_string)
71
+ end
72
+ end
73
+
74
+ context 'given a string with ` ` and `\'` characters' do
75
+ it 'should return a string with ` ` and `\'` both replaced by `_`' do
76
+ tested_string = 'a \'a'
77
+ expected_string = 'a__a'
78
+ expect(tested_string.urlize).to eql(expected_string)
79
+ end
80
+ end
81
+
82
+ context 'given a string with `-` and `_` characters or numbers' do
83
+ it 'should return the same string' do
84
+ tested_string = '-_0123456789'
85
+ expected_string = '-_0123456789'
86
+ expect(tested_string.urlize).to eql(expected_string)
87
+ end
88
+ end
89
+
90
+ context 'given a string with special characters only' do
91
+ it 'should return an empty string (special characters removed)' do
92
+ tested_string = '!"#$%&()*+,./:;<=>?@[\\]^`{|}~'
93
+ expected_string = ''
94
+ expect(tested_string.urlize).to eql(expected_string)
95
+ end
96
+ end
97
+
98
+ context 'given a string with characters from Code page 852 (Latin-2 DOS)' do
99
+ it 'should return the same string without accented nor special characters, downcased' do
100
+ tested_string1 = 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñѪº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐'
101
+ tested_string2 = '└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýݯ´≡±‗¾¶§÷¸°¨·¹³²■'
102
+ expected_string1 = 'cueaaaaceeeiiiaaeaeaeooouuyouooaiounnaaa'
103
+ expected_string2 = 'aaddeeeiiiiiossoooouuuyy'
104
+ expect(tested_string1.urlize).to eql(expected_string1)
105
+ expect(tested_string2.urlize).to eql(expected_string2)
106
+ end
107
+ end
108
+ end
109
+
110
+ describe '#urlized?' do
111
+ context 'given an empty string' do
112
+ it 'should return true' do
113
+ tested_string = ''
114
+ expect(tested_string.urlized?).to be true
115
+ end
116
+ end
117
+
118
+ context 'given a string containing only allowed characters' do
119
+ it 'should return true' do
120
+ tested_string = '-_abcdefghijklmnopqrstuvwxyz0123456789'
121
+ expect(tested_string.urlized?).to be true
122
+ end
123
+ end
124
+
125
+ context 'given a string containing at least only forbidden character' do
126
+ it 'should return false' do
127
+ tested_string1 = 'foo bar'
128
+ expect(tested_string1.urlized?).to be false
129
+ # ---
130
+ tested_string2 = 'fooBar'
131
+ expect(tested_string2.urlized?).to be false
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'core_extensions/tree'
4
+
5
+ RSpec.describe CoreExtensions::Tree do
6
+ describe '.initialize' do
7
+ context 'creating a new Tree' do
8
+ before do
9
+ @tree = described_class.new
10
+ end
11
+ it 'should return a Tree with no children' do
12
+ expect(@tree.children?).to be false
13
+ expect(@tree.children_nodes).to be_empty
14
+ end
15
+ it 'should return a Tree with root value equal to nil' do
16
+ expect(@tree.value).to be_nil
17
+ end
18
+ end
19
+
20
+ context 'creating a new Tree with a root VALUE' do
21
+ before do
22
+ @tree = described_class.new(42)
23
+ end
24
+ it 'should return a Tree with no children' do
25
+ expect(@tree.children?).to be false
26
+ expect(@tree.children_nodes).to be_empty
27
+ end
28
+ it 'should return a Tree with root value equal to VALUE' do
29
+ expect(@tree.value).to eql(42)
30
+ end
31
+ end
32
+ end
33
+
34
+ describe '#add_child_node' do
35
+ context 'given a child ID' do
36
+ before do
37
+ @tree = described_class.new
38
+ @ref = @tree.add_child_node('first')
39
+ end
40
+ it 'should add a new child node to the Tree, identified by ID and holding nil value' do
41
+ expect(@tree.children?).to be true
42
+ expect(@tree.children_nodes.size).to be_eql(1)
43
+ expect(@tree.child_exists?('first')).to be true
44
+ expect(@tree.child_node('first').value).to be_nil
45
+ end
46
+ it 'should return a reference to the newly created child node' do
47
+ expect(@ref).to be(@tree.child_node('first'))
48
+ end
49
+ end
50
+
51
+ context 'given a child ID and a VALUE' do
52
+ before do
53
+ @tree = described_class.new
54
+ @ref = @tree.add_child_node('first', 43)
55
+ end
56
+ it 'should add a new child node to the Tree, identified by ID and holding VALUE' do
57
+ expect(@tree.children?).to be true
58
+ expect(@tree.children_nodes.size).to be_eql(1)
59
+ expect(@tree.child_exists?('first')).to be true
60
+ expect(@tree.child_node('first').value).to be_eql(43)
61
+ end
62
+ it 'should return a reference to the newly created child node' do
63
+ expect(@ref).to be(@tree.child_node('first'))
64
+ end
65
+ end
66
+
67
+ context 'given a child ID corresponding to an existing child' do
68
+ before do
69
+ @tree = described_class.new
70
+ @ref1 = @tree.add_child_node('first', 43)
71
+ @ref2 = @tree.add_child_node('first', 44)
72
+ end
73
+ it 'should left the tree unchanged' do
74
+ expect(@tree.children?).to be true
75
+ expect(@tree.children_nodes.size).to be_eql(1)
76
+ expect(@tree.child_exists?('first')).to be true
77
+ expect(@tree.child_node('first').value).to be_eql(43)
78
+ end
79
+ it 'should return a reference to the existing child with given ID' do
80
+ expect(@ref2).to be(@ref1)
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#child_exists' do
86
+ context 'given a non-existant child ID' do
87
+ before do
88
+ @tree = described_class.new
89
+ @tree.add_child_node('first')
90
+ end
91
+ it 'should return false' do
92
+ expect(@tree.child_exists?('second')).to be false
93
+ end
94
+ end
95
+ end
96
+
97
+ describe '#child_node' do
98
+ context 'given a non-existant child ID' do
99
+ before do
100
+ @tree = described_class.new
101
+ @tree.add_child_node('first')
102
+ end
103
+ it 'should raise KeyError' do
104
+ expect { @tree.child_node('second') }.to raise_error(KeyError)
105
+ end
106
+ end
107
+ end
108
+
109
+ describe '#to_h' do
110
+ context 'given a 10-nodes Tree' do
111
+ before do
112
+ @tree = described_class.new('node0')
113
+ @tree.add_child_node('left', 'node1')
114
+ @tree.add_child_node('middle', 'node2')
115
+ @tree.add_child_node('right', 'node3')
116
+ @tree.child_node('left').add_child_node('left', 'node1.1')
117
+ @tree.child_node('left').add_child_node('right', 'node1.2')
118
+ @tree.child_node('middle').add_child_node('middle', 'node2.1')
119
+ @tree.child_node('right').add_child_node('left', 'node3.1')
120
+ @tree.child_node('right').add_child_node('middle', 'node3.2')
121
+ @tree.child_node('right').add_child_node('right', 'node3.3')
122
+ end
123
+ it 'should return a depth-first representation of the Tree' do
124
+ expect(@tree.to_h).to eql(
125
+ Hash['/' => 'node0',
126
+ '/left' => 'node1',
127
+ '/left/left' => 'node1.1',
128
+ '/left/right' => 'node1.2',
129
+ '/middle' => 'node2',
130
+ '/middle/middle' => 'node2.1',
131
+ '/right' => 'node3',
132
+ '/right/left' => 'node3.1',
133
+ '/right/middle' => 'node3.2',
134
+ '/right/right' => 'node3.3']
135
+ )
136
+ end
137
+ end
138
+
139
+ context 'given a 10-nodes Tree and a separator' do
140
+ before do
141
+ @tree = described_class.new(0.0)
142
+ @tree.add_child_node('left', 1.0)
143
+ @tree.add_child_node('middle', 2.0)
144
+ @tree.add_child_node('right', 3.0)
145
+ @tree.child_node('left').add_child_node('left', 1.1)
146
+ @tree.child_node('left').add_child_node('right', 1.2)
147
+ @tree.child_node('middle').add_child_node('middle', 2.1)
148
+ @tree.child_node('right').add_child_node('left', 3.1)
149
+ @tree.child_node('right').add_child_node('middle', 3.2)
150
+ @tree.child_node('right').add_child_node('right', 3.3)
151
+ end
152
+ it 'should return a depth-first representation of the Tree, using the given separator' do
153
+ expect(@tree.to_h(':')).to eql(
154
+ Hash[':' => 0.0,
155
+ ':left' => 1.0,
156
+ ':left:left' => 1.1,
157
+ ':left:right' => 1.2,
158
+ ':middle' => 2.0,
159
+ ':middle:middle' => 2.1,
160
+ ':right' => 3.0,
161
+ ':right:left' => 3.1,
162
+ ':right:middle' => 3.2,
163
+ ':right:right' => 3.3]
164
+ )
165
+ end
166
+ end
167
+ end
168
+
169
+ describe '#to_s' do
170
+ context 'given a 10-nodes Tree' do
171
+ before do
172
+ @tree = described_class.new(0.0)
173
+ @tree.add_child_node('left', 1.0)
174
+ @tree.add_child_node('middle', 2.0)
175
+ @tree.add_child_node('right', 3.0)
176
+ @tree.child_node('left').add_child_node('left', 1.1)
177
+ @tree.child_node('left').add_child_node('right', 1.2)
178
+ @tree.child_node('middle').add_child_node('middle', 2.1)
179
+ @tree.child_node('right').add_child_node('left', 3.1)
180
+ @tree.child_node('right').add_child_node('middle', 3.2)
181
+ @tree.child_node('right').add_child_node('right', 3.3)
182
+ end
183
+ it 'should return an ASCII representation of the Tree' do
184
+ expect(@tree.to_s).to eql(
185
+ "VALUE: 0.0\n" \
186
+ " * ID: 'left'\n" \
187
+ " VALUE: 1.0\n" \
188
+ " * ID: 'left'\n" \
189
+ " VALUE: 1.1\n" \
190
+ " * ID: 'right'\n"\
191
+ " VALUE: 1.2\n" \
192
+ " * ID: 'middle'\n" \
193
+ " VALUE: 2.0\n" \
194
+ " * ID: 'middle'\n" \
195
+ " VALUE: 2.1\n" \
196
+ " * ID: 'right'\n" \
197
+ " VALUE: 3.0\n" \
198
+ " * ID: 'left'\n" \
199
+ " VALUE: 3.1\n" \
200
+ " * ID: 'middle'\n" \
201
+ " VALUE: 3.2\n" \
202
+ " * ID: 'right'\n" \
203
+ " VALUE: 3.3\n"
204
+ )
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'core_extensions/webrick/httpresponse'
4
+ require 'intranet/core/haml_wrapper'
5
+ require 'intranet/core/locales'
6
+
7
+ RSpec.describe CoreExtensions::WEBrick::HTTPResponse do
8
+ before do
9
+ Intranet::Core::Locales.initialize
10
+ Intranet::Core::HamlWrapper.initialize
11
+ WEBrick::HTTPResponse.include described_class
12
+ @httpresponse = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
13
+ end
14
+
15
+ describe '#create_error_page' do
16
+ context 'with an error code' do
17
+ before do
18
+ @httpresponse.status = 404
19
+ @httpresponse.create_error_page
20
+ end
21
+ it 'should return a customized error page for that error code' do
22
+ expect(@httpresponse.body).to eql(
23
+ "<!DOCTYPE html>\n<html>\n<head>\n" \
24
+ "<title>\n#{HTMLEntities.new.encode(I18n.t('nav.error.http'), :named)} 404 | \n" \
25
+ "#{HTMLEntities.new.encode(I18n.t('nav.error.http_404.short'), :named)}\n</title>\n" \
26
+ "<meta charset='utf-8'>\n" \
27
+ "<link href='/design/favicon.ico' rel='icon' type='image/x-icon'>\n" \
28
+ "<link href='/design/style.css' rel='stylesheet' type='text/css'>\n" \
29
+ "</head>\n<body>\n<header>\n" \
30
+ "<h1>\n<a href='/index.html'>#{Socket.gethostname.capitalize}</a>\n</h1>\n" \
31
+ "</header>\n<main>\n<section id='error'>\n" \
32
+ "<h2>\n#{HTMLEntities.new.encode(I18n.t('nav.error.http'), :named)} 404\n<br>\n" \
33
+ "#{HTMLEntities.new.encode(I18n.t('nav.error.http_404.short'), :named)}" \
34
+ "\n</h2>\n<p>\n<img alt='' src='/design/error.png'>\n<br>\n" \
35
+ "#{HTMLEntities.new.encode(I18n.t('nav.error.http_404.full'), :named)}\n" \
36
+ "<br>\n<br>\n<a href='/index.html'>" \
37
+ "#{HTMLEntities.new.encode(I18n.t('nav.back.home'), :named)}</a>\n</p>\n</section>\n" \
38
+ "</main>\n<footer></footer>\n</body>\n</html>\n"
39
+ )
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ # fr.yml - Dummy translation file for intranet-core tests
2
+ ---
3
+
4
+ fr:
5
+ dummy: 'Stupide'
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'intranet/core/haml_wrapper'
4
+
5
+ RSpec.describe Intranet::Core::HamlWrapper do
6
+ describe '.initialize' do
7
+ before do
8
+ @load_path = File.absolute_path('../../../lib/intranet/resources/haml', __dir__)
9
+ described_class.initialize(@load_path)
10
+ end
11
+
12
+ it 'should define the default load path' do
13
+ expect(described_class.load_path).to eql([@load_path])
14
+ end
15
+ end
16
+
17
+ describe '.add_path' do
18
+ before do
19
+ @load_path = File.absolute_path('../../../lib/intranet/resources/haml', __dir__)
20
+ described_class.initialize(@load_path)
21
+ described_class.add_path(__dir__)
22
+ end
23
+
24
+ it 'should prepend the given directory to the HAML load path' do
25
+ expect(described_class.load_path.first).to eql(__dir__)
26
+ end
27
+ end
28
+
29
+ #---
30
+
31
+ let(:included) { Class.new { include Intranet::Core::HamlWrapper } }
32
+ let(:extended) { Class.new { extend Intranet::Core::HamlWrapper } }
33
+
34
+ describe 'to_markup' do
35
+ before do
36
+ described_class.initialize
37
+ end
38
+
39
+ context 'if the template is not found in path' do
40
+ before do
41
+ described_class.load_path = [] # empty load path
42
+ expect(described_class.load_path).to be_empty
43
+ end
44
+
45
+ it 'should return an empty string' do
46
+ expect(included.new.to_markup('')).to be_empty
47
+ expect(extended.to_markup('')).to be_empty
48
+
49
+ expect(included.new.to_markup('unknown')).to be_empty
50
+ expect(extended.to_markup('unknown')).to be_empty
51
+
52
+ expect(included.new.to_markup('title_and_breadcrumb')).to be_empty
53
+ expect(extended.to_markup('title_and_breadcrumb')).to be_empty
54
+ end
55
+ end
56
+
57
+ context 'given a valid HAML template and locals' do
58
+ test_in = { title: 'TITLE_1', nav: { 'link_1' => '/index.html', 'link_2' => nil } }
59
+ test_out = "<h2>TITLE_1</h2>\n" \
60
+ "<ul class='breadcrumb'>\n" \
61
+ "<li>\n<a href='/index.html'>link_1</a>\n</li>\n" \
62
+ "<li>link_2</li>\n" \
63
+ "</ul>\n"
64
+ it 'should generate the markup from template using locals value' do
65
+ expect(included.new.to_markup('title_and_breadcrumb', test_in)).to eql(test_out)
66
+ expect(extended.to_markup('title_and_breadcrumb', test_in)).to eql(test_out)
67
+ end
68
+ end
69
+ end
70
+ end