hs-cli 0.2.2 → 0.3.0

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