hs-cli 0.1.2
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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.hs.yml +2 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +86 -0
- data/LICENSE.txt +21 -0
- data/README.md +54 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/hs.gemspec +41 -0
- data/lib/hs/chapter.rb +31 -0
- data/lib/hs/config.rb +40 -0
- data/lib/hs/course.rb +35 -0
- data/lib/hs/elements/br.rb +9 -0
- data/lib/hs/elements/code.rb +22 -0
- data/lib/hs/elements/dd.rb +9 -0
- data/lib/hs/elements/dl.rb +9 -0
- data/lib/hs/elements/dt.rb +9 -0
- data/lib/hs/elements/element.rb +46 -0
- data/lib/hs/elements/emphasize.rb +9 -0
- data/lib/hs/elements/header.rb +16 -0
- data/lib/hs/elements/image.rb +22 -0
- data/lib/hs/elements/intro.rb +9 -0
- data/lib/hs/elements/li.rb +9 -0
- data/lib/hs/elements/link.rb +21 -0
- data/lib/hs/elements/note.rb +9 -0
- data/lib/hs/elements/ol.rb +9 -0
- data/lib/hs/elements/original.rb +9 -0
- data/lib/hs/elements/paragraph.rb +9 -0
- data/lib/hs/elements/strong.rb +9 -0
- data/lib/hs/elements/table.rb +39 -0
- data/lib/hs/elements/text.rb +21 -0
- data/lib/hs/elements/ul.rb +9 -0
- data/lib/hs/loaders/chapter_loader.rb +38 -0
- data/lib/hs/loaders/course_loader.rb +36 -0
- data/lib/hs/loaders/element_loader.rb +127 -0
- data/lib/hs/loaders/xml_parser.rb +62 -0
- data/lib/hs/preview/chapter_preview.rb +49 -0
- data/lib/hs/preview/course_preview.rb +43 -0
- data/lib/hs/preview/element_preview.rb +45 -0
- data/lib/hs/preview/html_preview.rb +27 -0
- data/lib/hs/version.rb +5 -0
- data/lib/hs.rb +28 -0
- metadata +231 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HS
|
4
|
+
class Table < HS::Element
|
5
|
+
def tag_name
|
6
|
+
'table'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Thead < HS::Element
|
11
|
+
def tag_name
|
12
|
+
'thead'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Tbody < HS::Element
|
17
|
+
def tag_name
|
18
|
+
'tbody'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Tr < HS::Element
|
23
|
+
def tag_name
|
24
|
+
'tr'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Th < HS::Element
|
29
|
+
def tag_name
|
30
|
+
'th'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Td < HS::Element
|
35
|
+
def tag_name
|
36
|
+
'td'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hs/preview/element_preview'
|
4
|
+
|
5
|
+
module HS
|
6
|
+
class Text
|
7
|
+
include ElementPreview
|
8
|
+
|
9
|
+
attr_accessor :text
|
10
|
+
|
11
|
+
def initialize(args)
|
12
|
+
args.each do |key, val|
|
13
|
+
instance_variable_set("@#{key}", val)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def preview
|
18
|
+
text_preview(text)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hs/loaders/xml_parser'
|
4
|
+
require 'hs/loaders/element_loader'
|
5
|
+
|
6
|
+
module HS
|
7
|
+
module ChapterLoader
|
8
|
+
include HS::XMLParser
|
9
|
+
include HS::ElementLoader
|
10
|
+
|
11
|
+
def load_chapter(course, xml)
|
12
|
+
create_chapter(course, parse_xml(xml))
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def create_chapter(course, data) # rubocop:disable Metrics/MethodLength
|
18
|
+
chapter = HS::Chapter.new(course, slug: data[:slug])
|
19
|
+
|
20
|
+
data[:_children].each do |child|
|
21
|
+
case child[:_name]
|
22
|
+
when :title
|
23
|
+
chapter.title = get_text(child)
|
24
|
+
when :intro
|
25
|
+
chapter.intro = load_element(child)
|
26
|
+
when :modules
|
27
|
+
# TODO: extract :modules
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
element = load_element(child)
|
31
|
+
chapter.content << element if element
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
chapter
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hs/loaders/xml_parser'
|
4
|
+
|
5
|
+
module HS
|
6
|
+
module CourseLoader
|
7
|
+
include HS::XMLParser
|
8
|
+
|
9
|
+
def load_course(xml, &block)
|
10
|
+
create_course(parse_xml(xml), &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def create_course(data) # rubocop:disable Metrics/MethodLength
|
16
|
+
course = HS::Course.new(slug: data[:slug])
|
17
|
+
|
18
|
+
data[:_children].each do |child|
|
19
|
+
case child[:_name]
|
20
|
+
when :title
|
21
|
+
course.title = get_text(child)
|
22
|
+
when :chapters
|
23
|
+
if block_given?
|
24
|
+
files = child[:_children].map { |c| c[:file] }.compact
|
25
|
+
|
26
|
+
files.each do |file|
|
27
|
+
yield course, file
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
course
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HS
|
4
|
+
module ElementLoader
|
5
|
+
def load_element(data)
|
6
|
+
name = data[:_name]
|
7
|
+
element = initialize_element(name, data)
|
8
|
+
children = load_elements(data[:_children])
|
9
|
+
children.each { |child| element.children << child }
|
10
|
+
|
11
|
+
element
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_elements(data)
|
15
|
+
return [] unless data
|
16
|
+
data.map { |child_data| load_element(child_data) }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def get_params(data, names = %i[class_name style])
|
22
|
+
names.map do |name|
|
23
|
+
data[name] ? [name, data[name]] : nil
|
24
|
+
end.compact.to_h
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize_header(data)
|
28
|
+
HS::Header.new(get_params(data, %i[level class_name style]))
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize_element(name, data)
|
32
|
+
send("initialize_#{name}", data)
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize_text(data)
|
36
|
+
HS::Text.new(text: data[:text])
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize_p(data)
|
40
|
+
HS::Paragraph.new(get_params(data))
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize_note(data)
|
44
|
+
HS::Note.new(get_params(data))
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize_intro(data)
|
48
|
+
HS::Intro.new(get_params(data))
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize_em(data)
|
52
|
+
HS::Emphasize.new(get_params(data))
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize_link(data)
|
56
|
+
HS::Link.new(get_params(data, %i[to class_name style]))
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize_original(data)
|
60
|
+
HS::Original.new(get_params(data))
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize_strong(data)
|
64
|
+
HS::Strong.new(get_params(data))
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize_ul(data)
|
68
|
+
HS::Ul.new(get_params(data))
|
69
|
+
end
|
70
|
+
|
71
|
+
def initialize_ol(data)
|
72
|
+
HS::Ol.new(get_params(data))
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize_li(data)
|
76
|
+
HS::Li.new(get_params(data))
|
77
|
+
end
|
78
|
+
|
79
|
+
def initialize_image(data)
|
80
|
+
HS::Image.new(get_params(data, %i[src class_name style]))
|
81
|
+
end
|
82
|
+
|
83
|
+
def initialize_code(data)
|
84
|
+
HS::Code.new(get_params(data, %i[lang class_name style]))
|
85
|
+
end
|
86
|
+
|
87
|
+
def initialize_dd(data)
|
88
|
+
HS::Dd.new(get_params(data))
|
89
|
+
end
|
90
|
+
|
91
|
+
def initialize_dl(data)
|
92
|
+
HS::Dl.new(get_params(data))
|
93
|
+
end
|
94
|
+
|
95
|
+
def initialize_dt(data)
|
96
|
+
HS::Dt.new(get_params(data))
|
97
|
+
end
|
98
|
+
|
99
|
+
def initialize_table(data)
|
100
|
+
HS::Table.new(get_params(data))
|
101
|
+
end
|
102
|
+
|
103
|
+
def initialize_thead(data)
|
104
|
+
HS::Thead.new(get_params(data))
|
105
|
+
end
|
106
|
+
|
107
|
+
def initialize_tbody(data)
|
108
|
+
HS::Tbody.new(get_params(data))
|
109
|
+
end
|
110
|
+
|
111
|
+
def initialize_tr(data)
|
112
|
+
HS::Tr.new(get_params(data))
|
113
|
+
end
|
114
|
+
|
115
|
+
def initialize_th(data)
|
116
|
+
HS::Th.new(get_params(data))
|
117
|
+
end
|
118
|
+
|
119
|
+
def initialize_td(data)
|
120
|
+
HS::Td.new(get_params(data))
|
121
|
+
end
|
122
|
+
|
123
|
+
def initialize_br(_data)
|
124
|
+
HS::Br.new # no params!
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
module HS
|
7
|
+
module XMLParser
|
8
|
+
def parse_xml(xml)
|
9
|
+
doc = Nokogiri::XML(xml) do |config|
|
10
|
+
config.options = Nokogiri::XML::ParseOptions::STRICT
|
11
|
+
end
|
12
|
+
|
13
|
+
to_object_notation(doc.root)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Text content of the node.
|
17
|
+
# Note, that we don't go deep into element tree.
|
18
|
+
def get_text(object)
|
19
|
+
object[:_children].map { |obj| obj[:text] }.compact.join(' ')
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def attributes_hash(xml)
|
25
|
+
xml.attributes.map do |key, attr|
|
26
|
+
[key.underscore.to_sym, attr.value]
|
27
|
+
end.to_h
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_object_notation(xml)
|
31
|
+
class_name = xml.class.name.split('::').last.downcase
|
32
|
+
send("#{class_name}_to_object_notation", xml)
|
33
|
+
end
|
34
|
+
|
35
|
+
def element_to_object_notation(xml)
|
36
|
+
data = attributes_hash(xml)
|
37
|
+
data[:_name] = xml.name.underscore.to_sym
|
38
|
+
data[:_children] = to_object_notation(xml.children)
|
39
|
+
|
40
|
+
data
|
41
|
+
end
|
42
|
+
|
43
|
+
def cdata_to_object_notation(xml)
|
44
|
+
text_to_object_notation(xml)
|
45
|
+
end
|
46
|
+
|
47
|
+
def text_to_object_notation(xml)
|
48
|
+
{
|
49
|
+
_name: :text,
|
50
|
+
text: xml.text
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def nodeset_to_object_notation(xml)
|
55
|
+
xml.map { |node| to_object_notation(node) }.compact
|
56
|
+
end
|
57
|
+
|
58
|
+
def comment_to_object_notation(_xml)
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hs/preview/html_preview'
|
4
|
+
|
5
|
+
module HS
|
6
|
+
module ChapterPreview
|
7
|
+
include HS::HTMLPreview
|
8
|
+
|
9
|
+
def preview
|
10
|
+
html_preview do
|
11
|
+
body_element
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def toc_preview
|
16
|
+
"<li><a href=\"/#{slug}\">#{title.strip}</a></li>"
|
17
|
+
end
|
18
|
+
|
19
|
+
def save_preview
|
20
|
+
file = "#{HS::Config.preview_dir}/#{slug}.html"
|
21
|
+
File.open(file, 'w') { |f| f.write(preview) }
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def body_element
|
27
|
+
[
|
28
|
+
'<body>',
|
29
|
+
title_preview,
|
30
|
+
intro_preview,
|
31
|
+
content_preview,
|
32
|
+
'</body>'
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
def intro_preview
|
37
|
+
return unless intro
|
38
|
+
intro.preview
|
39
|
+
end
|
40
|
+
|
41
|
+
def title_preview
|
42
|
+
"<h1 class=\"title\">#{title.strip}</h1>"
|
43
|
+
end
|
44
|
+
|
45
|
+
def content_preview
|
46
|
+
content.map(&:preview).compact.join
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hs/preview/html_preview'
|
4
|
+
|
5
|
+
module HS
|
6
|
+
module CoursePreview
|
7
|
+
include HS::HTMLPreview
|
8
|
+
|
9
|
+
def preview
|
10
|
+
html_preview do
|
11
|
+
body_element
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def save_preview
|
16
|
+
file = "#{HS::Config.preview_dir}/index.html"
|
17
|
+
File.open(file, 'w') { |f| f.write(preview) }
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def body_element
|
23
|
+
[
|
24
|
+
'<body>',
|
25
|
+
title_preview,
|
26
|
+
toc_preview,
|
27
|
+
'</body>'
|
28
|
+
].join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
def title_preview
|
32
|
+
" <h1 class=\"title\">#{title.strip}</h1>"
|
33
|
+
end
|
34
|
+
|
35
|
+
def toc_preview
|
36
|
+
[
|
37
|
+
' <ul>',
|
38
|
+
chapters.map(&:toc_preview).join("\n"),
|
39
|
+
' </ul>'
|
40
|
+
].join("\n")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module HS
|
6
|
+
module ElementPreview
|
7
|
+
def text_preview(text)
|
8
|
+
return unless text
|
9
|
+
CGI.escapeHTML(text)
|
10
|
+
end
|
11
|
+
|
12
|
+
def element_preview(tag_name, params, children)
|
13
|
+
[
|
14
|
+
element_start(tag_name, params, children),
|
15
|
+
element_content(children),
|
16
|
+
element_end(tag_name, children)
|
17
|
+
].join
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def element_start(tag, params, children)
|
23
|
+
start = "<#{tag}"
|
24
|
+
|
25
|
+
unless params.empty?
|
26
|
+
params_str = params.map { |k, v| "#{k}=\"#{v}\"" }.join(' ')
|
27
|
+
start = "#{start} #{params_str}"
|
28
|
+
end
|
29
|
+
|
30
|
+
return "#{start} />" if children.empty?
|
31
|
+
"#{start}>"
|
32
|
+
end
|
33
|
+
|
34
|
+
def element_content(children)
|
35
|
+
return if children.empty?
|
36
|
+
children.map(&:preview).compact.join
|
37
|
+
end
|
38
|
+
|
39
|
+
def element_end(tag, children)
|
40
|
+
return if children.empty?
|
41
|
+
|
42
|
+
"</#{tag}>"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HS
|
4
|
+
module HTMLPreview
|
5
|
+
def html_preview
|
6
|
+
body = yield
|
7
|
+
[
|
8
|
+
'<html>',
|
9
|
+
head_element,
|
10
|
+
body,
|
11
|
+
'</html>'
|
12
|
+
].compact.join("\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def head_element
|
18
|
+
[
|
19
|
+
'<head>',
|
20
|
+
'<meta charset="utf-8"/> ',
|
21
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1"/>',
|
22
|
+
'<link rel="stylesheet" href="/default.css"/>',
|
23
|
+
'</head>'
|
24
|
+
].join("\n")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/hs/version.rb
ADDED
data/lib/hs.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hs/version'
|
4
|
+
require 'hs/config'
|
5
|
+
|
6
|
+
require 'hs/course'
|
7
|
+
require 'hs/chapter'
|
8
|
+
|
9
|
+
require 'hs/elements/element'
|
10
|
+
require 'hs/elements/br'
|
11
|
+
require 'hs/elements/code'
|
12
|
+
require 'hs/elements/dd'
|
13
|
+
require 'hs/elements/dl'
|
14
|
+
require 'hs/elements/dt'
|
15
|
+
require 'hs/elements/emphasize'
|
16
|
+
require 'hs/elements/header'
|
17
|
+
require 'hs/elements/image'
|
18
|
+
require 'hs/elements/intro'
|
19
|
+
require 'hs/elements/li'
|
20
|
+
require 'hs/elements/link'
|
21
|
+
require 'hs/elements/note'
|
22
|
+
require 'hs/elements/ol'
|
23
|
+
require 'hs/elements/original'
|
24
|
+
require 'hs/elements/paragraph'
|
25
|
+
require 'hs/elements/strong'
|
26
|
+
require 'hs/elements/table'
|
27
|
+
require 'hs/elements/text'
|
28
|
+
require 'hs/elements/ul'
|