hs-cli 0.2.2 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40072df5da387c7cfd1ccdc4e5fded11d0667ced276d450edb99f4a648f8f9e1
4
- data.tar.gz: 8dfdca544def1246b7dabbe03ffa4c0fa4152d541c64300bfc92a96ba791594e
3
+ metadata.gz: 01dbde2079037eab73a7d0380810276f614fb6c6ea4dfbb607027f1261458c78
4
+ data.tar.gz: 375508cdfd0574107d515b080dcbe556084f4ad324ce59a586701e90266432a7
5
5
  SHA512:
6
- metadata.gz: a6061d9663674352d7e48825413e654d54e995a07db4f4b5ae1b70b6ac10987704ac28de4cfdd5616ce0505d046f25c5bdbbbe1f869f1a4882ace184c2a32ed0
7
- data.tar.gz: e572c9d98d09f2a630c0566a00876796d6d116f925fe514a0310fc5144158718a301b75bb8ab6760524e2d809b1226258192cc687ceec72b5acd5449625a4a49
6
+ metadata.gz: a6117a1462bc5a5f1e1ed1c2f7a708d8edd3054bde127b60cbb4db9340dddc7ceec0e2c81804435b15a2dc51c118cca57085fd0bedf3819121d54ae24ad019c5
7
+ data.tar.gz: 21b5cb8b8d1dd4b8e10f2997dd4c67175cc85cc403da8f25af4a35ec6995c51a5ef2a20c6cacdd3bbd1edab2589373b542ddd546ba91237c046e7a2fa1af73a9
data/.hs.yml CHANGED
@@ -1,2 +1 @@
1
1
  publish_url: http://hackerschool.ge
2
- preview_dir: previews
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hs-cli (0.2.2)
4
+ hs-cli (0.3.0)
5
5
  activesupport (~> 5.2)
6
6
  nokogiri (~> 1.8)
7
7
  rack-contrib (~> 2.0)
data/app/views/_nav.erb CHANGED
@@ -1,13 +1,24 @@
1
+ <% mod = defined?(mod) ? mod : nil %>
2
+
1
3
  <hr />
2
4
 
3
5
  <div class="uk-container">
4
6
  <ul class="uk-breadcrumb">
5
7
  <li>
6
- <a href="/"><%= course %></a>
7
- </li>
8
- <li>
9
- <span><%= chapter %></span>
8
+ <a href="/"><%= course.title %></a>
10
9
  </li>
10
+ <% if mod.nil? %>
11
+ <li>
12
+ <span><%= chapter.title %></span>
13
+ </li>
14
+ <% else %>
15
+ <li>
16
+ <a href="/<%= chapter.slug %>"><%= chapter.title %></a>
17
+ </li>
18
+ <li>
19
+ <span><%= mod.title %></span>
20
+ </li>
21
+ <% end %>
11
22
  </ul>
12
23
  </div>
13
24
 
@@ -9,13 +9,33 @@
9
9
  </p>
10
10
  </div>
11
11
 
12
- <%= erb :_nav, layout: false, locals: { course: @course.title, chapter: @chapter.title } %>
12
+ <%= erb :_nav, layout: false, locals: { course: @course, chapter: @chapter } %>
13
13
 
14
14
  <div class="uk-container">
15
15
  <%= @chapter.preview %>
16
16
  </div>
17
17
 
18
- <%= erb :_nav, layout: false, locals: { course: @course.title, chapter: @chapter.title } %>
18
+ <% unless @chapter.modules.empty? %>
19
+ <div class="uk-container">
20
+ <h2 class="toc-title">
21
+ <span uk-icon="icon: list"></span>
22
+ თავის შინაარსი
23
+ </h2>
24
+
25
+ <ol class="toc">
26
+ <% @chapter.modules.each do |mod| %>
27
+ <li>
28
+ <a href="/<%= @chapter.slug %>/<%= mod.slug %>" class="uk-text-<%= mod.review_color %>">
29
+ <span uk-icon="icon: <%= mod.review_icon %>"></span>
30
+ <%= mod.title %>
31
+ </a>
32
+ </li>
33
+ <% end %>
34
+ </ol>
35
+ </div>
36
+ <% end %>
37
+
38
+ <%= erb :_nav, layout: false, locals: { course: @course, chapter: @chapter } %>
19
39
 
20
40
  <%= erb :_footer, layout: false %>
21
41
  </div>
data/app/views/course.erb CHANGED
@@ -9,6 +9,7 @@
9
9
 
10
10
  <div class="uk-container">
11
11
  <h2 class="toc-title">
12
+ <span uk-icon="icon: list"></span>
12
13
  კურსის შინაარსი
13
14
  </h2>
14
15
 
@@ -0,0 +1,21 @@
1
+ <div class="uk-section">
2
+ <div class="uk-container">
3
+ <h1>
4
+ <%= @module.title %>
5
+ </h1>
6
+ <p class="uk-text-<%= @module.review_color %>">
7
+ <span uk-icon="icon: <%= @module.review_icon %>"></span>
8
+ <%= @module.review_title %>
9
+ </p>
10
+ </div>
11
+
12
+ <%= erb :_nav, layout: false, locals: { course: @course, chapter: @chapter, mod: @module } %>
13
+
14
+ <div class="uk-container">
15
+ <%= @module.preview %>
16
+ </div>
17
+
18
+ <%= erb :_nav, layout: false, locals: { course: @course, chapter: @chapter, mod: @module } %>
19
+
20
+ <%= erb :_footer, layout: false %>
21
+ </div>
data/lib/hs/config.rb CHANGED
@@ -8,16 +8,11 @@ module HS
8
8
  include Singleton
9
9
 
10
10
  DEFAULT_BASE_URL = 'http://hackerschool.ge'
11
- DEFAULT_PREVIEW_DIR = 'previews'
12
11
 
13
12
  def self.publish_url
14
13
  instance.publish_url
15
14
  end
16
15
 
17
- def self.preview_dir
18
- instance.preview_dir
19
- end
20
-
21
16
  def initialize
22
17
  @data = load_configuration
23
18
  end
@@ -26,10 +21,6 @@ module HS
26
21
  @data['publish_url'] || DEFAULT_BASE_URL
27
22
  end
28
23
 
29
- def preview_dir
30
- @data['preview_dir'] || DEFAULT_PREVIEW_DIR
31
- end
32
-
33
24
  private
34
25
 
35
26
  def load_configuration
data/lib/hs/devserver.rb CHANGED
@@ -13,6 +13,7 @@ module HS
13
13
  self.app = initialize_application(config)
14
14
  set_root_route
15
15
  set_chapter_route
16
+ set_module_route
16
17
  app
17
18
  end
18
19
 
@@ -50,14 +51,27 @@ module HS
50
51
  def set_chapter_route
51
52
  entry = self.entry
52
53
 
53
- app.get '/:slug' do
54
+ app.get '/:chapter' do
54
55
  @course = HS::Course.load(entry)
55
- @chapter = @course.find_chapter(params[:slug])
56
+ @chapter = @course.find_chapter(params[:chapter])
56
57
  @title = @chapter.title
57
58
 
58
59
  erb :chapter
59
60
  end
60
61
  end
62
+
63
+ def set_module_route
64
+ entry = self.entry
65
+
66
+ app.get '/:chapter/:module' do
67
+ @course = HS::Course.load(entry)
68
+ @chapter = @course.find_chapter(params[:chapter])
69
+ @module = @chapter.find_module(params[:module])
70
+ @title = @module.title
71
+
72
+ erb :module
73
+ end
74
+ end
61
75
  end
62
76
  end
63
77
  end
@@ -8,35 +8,41 @@ module HS
8
8
  include HS::XMLParser
9
9
  include HS::ElementLoader
10
10
 
11
- def load_chapter(course, xml)
12
- create_chapter(course, parse_xml(xml))
11
+ CUSTOM_LOADERS = %i[title intro modules].freeze
12
+
13
+ def load_chapter(course, xml, &block)
14
+ create_chapter(course, parse_xml(xml), &block)
13
15
  end
14
16
 
15
17
  private
16
18
 
17
- def create_chapter(course, data) # rubocop:disable Metrics/MethodLength
18
- chapter = HS::Chapter.new(
19
- course,
20
- slug: data[:slug],
21
- review_status: data[:review_status]
22
- )
23
-
24
- data[:_children].each do |child|
25
- case child[:_name]
26
- when :title
27
- chapter.title = get_text(child)
28
- when :intro
29
- chapter.intro = load_element(child)
30
- when :modules
31
- # TODO: extract :modules
32
- nil
33
- else
34
- element = load_element(child)
35
- chapter.content << element if element
36
- end
19
+ def create_chapter(course, data, &block)
20
+ chapter = HS::Chapter.new(course, data.slice(:slug, :review_status))
21
+ data[:_children].each { |child| load_a_part(chapter, child, &block) }
22
+ chapter
23
+ end
24
+
25
+ def load_a_part(chapter, child, &block)
26
+ if CUSTOM_LOADERS.include?(child[:_name])
27
+ send("load_#{child[:_name]}", chapter, child, &block)
28
+ else
29
+ element = load_element(child)
30
+ chapter.content << element if element
37
31
  end
32
+ end
38
33
 
39
- chapter
34
+ def load_title(chapter, child)
35
+ chapter.title = get_text(child)
36
+ end
37
+
38
+ def load_intro(chapter, child)
39
+ chapter.intro = load_element(child)
40
+ end
41
+
42
+ def load_modules(chapter, child)
43
+ return unless block_given?
44
+ files = child[:_children].map { |m| m[:file] }.compact
45
+ files.each { |file| yield chapter, file }
40
46
  end
41
47
  end
42
48
  end
@@ -6,31 +6,33 @@ module HS
6
6
  module CourseLoader
7
7
  include HS::XMLParser
8
8
 
9
+ KNOWN_LOADERS = %i[title chapters].freeze
10
+
9
11
  def load_course(xml, &block)
10
12
  create_course(parse_xml(xml), &block)
11
13
  end
12
14
 
13
15
  private
14
16
 
15
- def create_course(data) # rubocop:disable Metrics/MethodLength
16
- course = HS::Course.new(slug: data[:slug])
17
+ def create_course(data, &block)
18
+ course = HS::Course.new(data.slice(:slug))
19
+ data[:_children].each { |child| load_a_part(course, child, &block) }
20
+ course
21
+ end
17
22
 
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
23
+ def load_a_part(course, child, &block)
24
+ return unless KNOWN_LOADERS.include?(child[:_name])
25
+ send("load_#{child[:_name]}", course, child, &block)
26
+ end
25
27
 
26
- files.each do |file|
27
- yield course, file
28
- end
29
- end
30
- end
31
- end
28
+ def load_title(course, child)
29
+ course.title = get_text(child)
30
+ end
32
31
 
33
- course
32
+ def load_chapters(course, child)
33
+ return unless block_given?
34
+ files = child[:_children].map { |c| c[:file] }.compact
35
+ files.each { |file| yield course, file }
34
36
  end
35
37
  end
36
38
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hs/loaders/xml_parser'
4
+ require 'hs/loaders/element_loader'
5
+
6
+ module HS
7
+ module ModuleLoader
8
+ include HS::XMLParser
9
+ include HS::ElementLoader
10
+
11
+ CUSTOM_LOADERS = %i[title intro].freeze
12
+
13
+ def load_module(chapter, xml)
14
+ create_module(chapter, parse_xml(xml))
15
+ end
16
+
17
+ private
18
+
19
+ def create_module(chapter, data)
20
+ mod = HS::Module.new(chapter, data.slice(:slug, :review_status))
21
+ data[:_children].each { |child| load_a_part(mod, child) }
22
+ mod
23
+ end
24
+
25
+ def load_a_part(mod, child)
26
+ if CUSTOM_LOADERS.include?(child[:_name])
27
+ send("load_#{child[:_name]}", mod, child)
28
+ else
29
+ element = load_element(child)
30
+ mod.content << element if element
31
+ end
32
+ end
33
+
34
+ def load_title(mod, child)
35
+ mod.title = get_text(child)
36
+ end
37
+
38
+ def load_intro(mod, child)
39
+ mod.intro = load_element(child)
40
+ end
41
+ end
42
+ end
@@ -1,37 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'hs/loaders/chapter_loader'
4
- require 'hs/preview/chapter_preview'
4
+ require 'hs/preview/content_preview'
5
+ require 'hs/models/review_status'
5
6
 
6
7
  module HS
7
8
  class Chapter
8
9
  extend HS::ChapterLoader
9
- include HS::ChapterPreview
10
-
11
- REVIEW_STATUSES = %w[none translated first second final].freeze
10
+ include HS::ContentPreview
11
+ include HS::ReviewStatus
12
12
 
13
+ # Loads chapter from file.
13
14
  def self.load(course, file)
14
- load_chapter(course, File.read(file))
15
+ dir = File.dirname(file)
16
+
17
+ load_chapter(course, File.read(file)) do |chapter, module_file|
18
+ path = "#{dir}/#{module_file}"
19
+ chapter.modules << HS::Module.load(chapter, path)
20
+ end
15
21
  end
16
22
 
17
- attr_reader :course, :content
23
+ attr_reader :course, :content, :modules
18
24
  attr_accessor :slug, :title, :intro
19
- attr_writer :review_status
20
25
 
21
26
  def initialize(course, args)
22
27
  @course = course
23
28
  @content = []
29
+ @modules = []
24
30
 
25
31
  args.each do |key, val|
26
32
  instance_variable_set("@#{key}", val)
27
33
  end
28
34
  end
29
35
 
30
- def review_status
31
- return 'none' unless REVIEW_STATUSES.include?(@review_status)
32
- @review_status
36
+ # Tries to find module in this chapter by module slug.
37
+ def find_module(slug)
38
+ modules.find { |m| m.slug.to_s == slug.to_s }
33
39
  end
34
40
 
41
+ # URL of this chapter when published.
35
42
  def hs_url
36
43
  "#{course.hs_url}/#{slug}"
37
44
  end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'hs/loaders/course_loader'
4
- require 'hs/preview/course_preview'
5
4
 
6
5
  module HS
6
+ # {HS::Course} is a top level model for a course.
7
7
  class Course
8
8
  extend HS::CourseLoader
9
- include HS::CoursePreview
10
9
 
10
+ # Load course from given XML file.
11
11
  def self.load(file)
12
12
  dir = File.dirname(file)
13
13
 
@@ -21,17 +21,19 @@ module HS
21
21
  attr_reader :chapters
22
22
 
23
23
  def initialize(args)
24
+ @chapters = []
25
+
24
26
  args.each do |key, val|
25
27
  instance_variable_set("@#{key}", val)
26
28
  end
27
-
28
- @chapters = []
29
29
  end
30
30
 
31
+ # Tries to find chapter in this course by chapter slug.
31
32
  def find_chapter(slug)
32
- chapters.find { |c| c.slug == slug }
33
+ chapters.find { |c| c.slug.to_s == slug.to_s }
33
34
  end
34
35
 
36
+ # URL of this course when published.
35
37
  def hs_url
36
38
  "#{HS::Config.publish_url}/learn/#{slug}"
37
39
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hs/loaders/module_loader'
4
+ require 'hs/preview/content_preview'
5
+ require 'hs/models/review_status'
6
+
7
+ module HS
8
+ class Module
9
+ extend HS::ModuleLoader
10
+ include HS::ContentPreview
11
+ include HS::ReviewStatus
12
+
13
+ attr_reader :chapter, :content
14
+ attr_accessor :slug, :title, :intro
15
+
16
+ def self.load(chapter, file)
17
+ load_module(chapter, File.read(file))
18
+ end
19
+
20
+ def initialize(chapter, args)
21
+ @chapter = chapter
22
+ @content = []
23
+
24
+ args.each do |key, val|
25
+ instance_variable_set("@#{key}", val)
26
+ end
27
+ end
28
+
29
+ # URL of this module when published.
30
+ def hs_url
31
+ "#{chapter.hs_url}/#{slug}"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HS
4
+ module ReviewStatus
5
+ # Possible values for review status:
6
+ #
7
+ # - `none` not reviewed and/or not translated, needs edit or translation
8
+ # - `translated` initial translatation was done, needs edit
9
+ # - `first` first editorial review was done
10
+ # - `second` second editorial review was done
11
+ # - `final` final editorial review was done
12
+ REVIEW_STATUSES = %w[none translated first second final].freeze
13
+
14
+ attr_writer :review_status
15
+
16
+ def review_status
17
+ return 'none' unless REVIEW_STATUSES.include?(@review_status)
18
+ @review_status
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hs/preview/review_status_preview'
4
+
5
+ module HS
6
+ module ContentPreview
7
+ include HS::ReviewStatusPreview
8
+
9
+ def preview
10
+ [
11
+ intro_preview,
12
+ content_preview
13
+ ].compact.join("\n")
14
+ end
15
+
16
+ private
17
+
18
+ def intro_preview
19
+ return unless intro
20
+ intro.preview
21
+ end
22
+
23
+ def content_preview
24
+ content.map(&:preview).compact.join
25
+ end
26
+ end
27
+ end
@@ -1,11 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'hs/preview/html_preview'
4
-
5
3
  module HS
6
- module ChapterPreview
7
- include HS::HTMLPreview
8
-
4
+ module ReviewStatusPreview
9
5
  REVIEW_ICON = {
10
6
  none: 'file',
11
7
  translated: 'bookmark',
@@ -30,10 +26,6 @@ module HS
30
26
  final: 'საბოლოო რედაქცია'
31
27
  }.freeze
32
28
 
33
- def preview
34
- body_element
35
- end
36
-
37
29
  def review_icon
38
30
  REVIEW_ICON[review_status.to_sym]
39
31
  end
@@ -45,23 +37,5 @@ module HS
45
37
  def review_color
46
38
  REVIEW_COLOR[review_status.to_sym]
47
39
  end
48
-
49
- private
50
-
51
- def body_element
52
- [
53
- intro_preview,
54
- content_preview
55
- ].join("\n")
56
- end
57
-
58
- def intro_preview
59
- return unless intro
60
- intro.preview
61
- end
62
-
63
- def content_preview
64
- content.map(&:preview).compact.join
65
- end
66
40
  end
67
41
  end
data/lib/hs/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HS
4
- VERSION = '0.2.2'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/hs.rb CHANGED
@@ -5,6 +5,7 @@ require 'hs/config'
5
5
 
6
6
  require 'hs/models/course'
7
7
  require 'hs/models/chapter'
8
+ require 'hs/models/module'
8
9
 
9
10
  require 'hs/elements/element'
10
11
  require 'hs/elements/br'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hs-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Kurashvili
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-26 00:00:00.000000000 Z
11
+ date: 2018-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -218,6 +218,7 @@ files:
218
218
  - app/views/chapter.erb
219
219
  - app/views/course.erb
220
220
  - app/views/layout.erb
221
+ - app/views/module.erb
221
222
  - bin/console
222
223
  - bin/setup
223
224
  - exe/hscli
@@ -248,13 +249,15 @@ files:
248
249
  - lib/hs/loaders/chapter_loader.rb
249
250
  - lib/hs/loaders/course_loader.rb
250
251
  - lib/hs/loaders/element_loader.rb
252
+ - lib/hs/loaders/module_loader.rb
251
253
  - lib/hs/loaders/xml_parser.rb
252
254
  - lib/hs/models/chapter.rb
253
255
  - lib/hs/models/course.rb
254
- - lib/hs/preview/chapter_preview.rb
255
- - lib/hs/preview/course_preview.rb
256
+ - lib/hs/models/module.rb
257
+ - lib/hs/models/review_status.rb
258
+ - lib/hs/preview/content_preview.rb
256
259
  - lib/hs/preview/element_preview.rb
257
- - lib/hs/preview/html_preview.rb
260
+ - lib/hs/preview/review_status_preview.rb
258
261
  - lib/hs/version.rb
259
262
  homepage: http://github.com/hackersrc/hs-cli
260
263
  licenses:
@@ -1,43 +0,0 @@
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
@@ -1,27 +0,0 @@
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