lessons_indexer 0.0.2.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ module LessonsIndexer
2
+ module Models
3
+ class Heading < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ module LessonsIndexer
2
+ module Models
3
+ class Lesson < Base
4
+ NAME_PATTERN = /(?<minor_major>(?<major>(\d+))(?:\.|-)(?<minor>(\d+)))(?<ext>\.md)/i
5
+ attr_reader :name
6
+
7
+ def initialize(file_name)
8
+ super file_name
9
+ @name = file_name.gsub(NAME_PATTERN, ' \k<minor_major>').titlecase
10
+ end
11
+
12
+ def link(dir)
13
+ "* [#{name}](#{dir}/#{file_name})\n"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -18,14 +18,14 @@ module LessonsIndexer
18
18
  begin
19
19
  Slop.parse(argv, strict: true, help: true,
20
20
  banner: 'Welcome to Lessons Indexer. Here is the list of available options:') do |o|
21
- o.string '-p', '--path', 'Path to the directory with the course', default: '.'#, argument: true
21
+ o.string '-p', '--path', 'Path to the directory with the course', default: '.'
22
22
  o.bool '-s', '--skip_index', 'Skip index generation for the course', default: false
23
- o.string '-o', '--output', 'Output file', default: 'README.md'#, as: String, argument: true
23
+ o.string '-o', '--output', 'Output file', default: 'README.md'
24
24
  o.bool '-g', '--git', 'Push changes to the remote Git branch?', default: false
25
- o.string '-m', '--message', 'Commit message', default: 'Added index'#, as: String, argument: true
25
+ o.string '-m', '--message', 'Commit message', default: 'Added index'
26
26
  o.bool '-a', '--all', 'Work with all branches (except for master)', default: false
27
27
  o.bool '-i', '--headings', 'Add heading images to the beginning of the lesson files?', default: false
28
- o.string '-d', '--headings_dir', 'Relative path to the directory with heading images', default: 'headers'#, as: String, argument: true
28
+ o.string '-d', '--headings_dir', 'Relative path to the directory with heading images', default: 'headings'
29
29
  end.to_hash
30
30
  rescue Slop::Error => e
31
31
  exit_msg e.message
@@ -7,7 +7,7 @@ module LessonsIndexer
7
7
  end
8
8
 
9
9
  def start!
10
- with_messages("Welcome to Lessons Indexer ver#{LessonsIndexer::VERSION}!", "=== [ DONE. ] ===", false) do
10
+ with_messages("=== [ Welcome to Lessons Indexer ver#{LessonsIndexer::VERSION}! ] ===", "=== [ DONE. ] ===", false) do
11
11
  indexer = Indexer.new(options)
12
12
 
13
13
  within options.path do
@@ -15,27 +15,14 @@ module LessonsIndexer
15
15
  brancher = GitManager::Brancher.new
16
16
  brancher.get_branches.each do |branch|
17
17
  brancher.within_branch branch do
18
- work_with indexer
18
+ indexer.do_work!
19
19
  end
20
20
  end
21
21
  else
22
- work_with indexer
22
+ indexer.do_work!
23
23
  end
24
24
  end
25
25
  end
26
26
  end
27
-
28
- private
29
-
30
- def work_with(indexer)
31
- indexer.build_index! unless options.skip_index
32
- indexer.add_headings! if options.headings
33
- git_push! if options.git
34
- end
35
-
36
- def git_push!
37
- pusher = GitManager::Pusher.new(options.message)
38
- pusher.push!
39
- end
40
27
  end
41
28
  end
@@ -1,3 +1,3 @@
1
1
  module LessonsIndexer
2
- VERSION = "0.0.2.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -1,30 +1,28 @@
1
- module LessonsIndexer
2
- RSpec.describe Writer do
3
- before :each do
4
- @writer = Writer.new('test.txt')
5
- @writer << 'test'
6
- end
7
- after(:all) {File.delete('test.txt')}
1
+ RSpec.describe LessonsIndexer::Addons::FileManager::Writer do
2
+ before :each do
3
+ @writer = described_class.new('test.txt')
4
+ @writer << 'test'
5
+ end
6
+ after(:all) {File.delete('test.txt')}
8
7
 
9
- specify "#name" do
10
- expect(@writer.name).to eq('test.txt')
11
- end
8
+ specify "#name" do
9
+ expect(@writer.name).to eq('test.txt')
10
+ end
12
11
 
13
- specify "#<<" do
14
- contents = IO.read(@writer.name)
15
- expect(contents).to eq('test')
16
- end
12
+ specify "#<<" do
13
+ contents = IO.read(@writer.name)
14
+ expect(contents).to eq('test')
15
+ end
17
16
 
18
- context "#prepend_data" do
19
- before(:each) {@writer.prepend_data('prepended')}
20
- it "should add data to the beginning" do
21
- expect(IO.read(@writer.name)).to eq('prependedtest')
22
- end
17
+ context "#prepend_data" do
18
+ before(:each) {@writer.prepend_data('prepended')}
19
+ it "should add data to the beginning" do
20
+ expect(IO.read(@writer.name)).to eq('prependedtest')
21
+ end
23
22
 
24
- it "should not add data to the beginning if data is already present" do
25
- @writer.prepend_data('prepended')
26
- expect(IO.read(@writer.name)).to eq('prependedtest')
27
- end
23
+ it "should not add data to the beginning if data is already present" do
24
+ @writer.prepend_data('prepended')
25
+ expect(IO.read(@writer.name)).to eq('prependedtest')
28
26
  end
29
27
  end
30
28
  end
@@ -0,0 +1,23 @@
1
+ RSpec.describe LessonsIndexer::Addons::GitManager::Pusher do
2
+ subject {described_class.new('test message')}
3
+
4
+ specify "#message" do
5
+ expect(subject.message).to eq('test message')
6
+ end
7
+
8
+ specify { expect(subject).to respond_to(:push!) }
9
+ end
10
+
11
+ RSpec.describe LessonsIndexer::Addons::GitManager::Brancher do
12
+ subject {described_class.new(false)}
13
+
14
+ specify "#ignore_master" do
15
+ expect(subject.ignore_master).to eq(false)
16
+ end
17
+
18
+ specify { expect(subject).to respond_to(:within_branch) }
19
+
20
+ specify "#get_branches" do
21
+ expect(subject.get_branches).to include 'master'
22
+ end
23
+ end
@@ -1,66 +1,64 @@
1
- module Kernel
2
- RSpec.describe "helper utils" do
3
- context "#within" do
4
- before(:all) {@original_path = Dir.getwd}
5
- after(:each) {Dir.chdir(@original_path)}
1
+ RSpec.describe Kernel do
2
+ context "#within" do
3
+ before(:all) {@original_path = Dir.getwd}
4
+ after(:each) {Dir.chdir(@original_path)}
6
5
 
7
- it "should return result of the block" do
8
- expect(Kernel.within('/') {1 + 1}).to eq(2)
9
- end
10
-
11
- it "should return immediately if no block is given" do
12
- expect(Kernel.within('/')).to eq(nil)
13
- end
14
-
15
- it "should raise an error if directory does not exist" do
16
- err = capture_stderr do
17
- expect(-> { Kernel.within('non_existent_dir') {1 + 1} }).to raise_error(SystemExit)
18
- end.uncolorize
19
- expect(err).to eq("[ERROR] The provided directory non_existent_dir was not found! Aborting...\n")
20
- end
6
+ it "should return result of the block" do
7
+ expect(described_class.within('/') {1 + 1}).to eq(2)
8
+ end
21
9
 
22
- it "should return to the original directory" do
23
- Kernel.within('/', true) {1 + 1}
24
- expect(Dir.getwd).to eq(@original_path)
25
- end
10
+ it "should return immediately if no block is given" do
11
+ expect(described_class.within('/')).to eq(nil)
12
+ end
26
13
 
27
- it "should not return to the original directory by default" do
28
- Kernel.within('/') {1 + 1}
29
- expect(Dir.getwd).not_to eq(@original_path)
30
- end
14
+ it "should raise an error if directory does not exist" do
15
+ err = capture_stderr do
16
+ expect(-> { described_class.within('non_existent_dir') {1 + 1} }).to raise_error(SystemExit)
17
+ end.uncolorize
18
+ expect(err).to eq("[ERROR] The provided directory non_existent_dir was not found! Aborting...\n")
31
19
  end
32
20
 
33
- context "#with_messages" do
34
- let(:after_msg) {"after"}
35
- let(:before_msg) {"before"}
36
- it "should handle block and display messages and delimiter" do
37
- info = capture_stdout do
38
- with_messages(before_msg, after_msg) { 1 + 1 }
39
- end.uncolorize
40
- expect(info).to eq("#{before_msg}\n#{after_msg}\n#{'=' * 50}\n")
41
- end
21
+ it "should return to the original directory" do
22
+ described_class.within('/', true) {1 + 1}
23
+ expect(Dir.getwd).to eq(@original_path)
24
+ end
42
25
 
43
- it "should not display delimiter when false is passed" do
44
- info = capture_stdout do
45
- with_messages(before_msg, after_msg, false) { 1 + 1 }
46
- end.uncolorize
47
- expect(info).to eq("#{before_msg}\n#{after_msg}\n")
48
- end
26
+ it "should not return to the original directory by default" do
27
+ described_class.within('/') {1 + 1}
28
+ expect(Dir.getwd).not_to eq(@original_path)
49
29
  end
30
+ end
50
31
 
51
- specify "#warning" do
52
- expect(Kernel).to respond_to(:warning)
53
- err = capture_stderr do
54
- warning "alert"
32
+ context "#with_messages" do
33
+ let(:after_msg) {"after"}
34
+ let(:before_msg) {"before"}
35
+ it "should handle block and display messages and delimiter" do
36
+ info = capture_stdout do
37
+ with_messages(before_msg, after_msg) { 1 + 1 }
55
38
  end.uncolorize
56
- expect(err).to eq("[WARNING] alert\n")
39
+ expect(info).to eq("#{before_msg}\n#{after_msg}\n#{'=' * 50}\n")
57
40
  end
58
41
 
59
- specify "#exit_msg" do
60
- err = capture_stderr do
61
- expect(-> {exit_msg('critical')}).to raise_error(SystemExit)
42
+ it "should not display delimiter when false is passed" do
43
+ info = capture_stdout do
44
+ with_messages(before_msg, after_msg, false) { 1 + 1 }
62
45
  end.uncolorize
63
- expect(err).to eq("[ERROR] critical\n")
46
+ expect(info).to eq("#{before_msg}\n#{after_msg}\n")
64
47
  end
65
48
  end
49
+
50
+ specify "#warning" do
51
+ expect(described_class).to respond_to(:warning)
52
+ err = capture_stderr do
53
+ warning "alert"
54
+ end.uncolorize
55
+ expect(err).to eq("[WARNING] alert\n")
56
+ end
57
+
58
+ specify "#exit_msg" do
59
+ err = capture_stderr do
60
+ expect(-> {exit_msg('critical')}).to raise_error(SystemExit)
61
+ end.uncolorize
62
+ expect(err).to eq("[ERROR] critical\n")
63
+ end
66
64
  end
@@ -0,0 +1,28 @@
1
+ RSpec.describe LessonsIndexer::Collections::HeadingsList do
2
+ subject { sample_headings }
3
+
4
+ context "#for" do
5
+ it "should return heading for a lesson" do
6
+ lesson = double('lesson', major: 2, minor: 5)
7
+ expect(subject.for(lesson)).to eq(subject.first)
8
+ end
9
+
10
+ it "should return nil if heading does not exist" do
11
+ lesson = double('lesson', major: 10, minor: 5)
12
+ expect(subject.for(lesson)).to be_nil
13
+ end
14
+ end
15
+
16
+ context "#list" do
17
+ it "should respond to #each" do
18
+ expect(subject).to respond_to(:each)
19
+ end
20
+
21
+ it "should be sorted properly" do
22
+ sorted_headings = subject.sort
23
+ %w(1.3 2.5 5.8 10.2).each_with_index do |version, index|
24
+ expect(sorted_headings[index].file_name).to eq "lesson#{version}.jpg"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ RSpec.describe LessonsIndexer::Collections::LessonsList do
2
+ subject { sample_lessons }
3
+
4
+ context "#list" do
5
+ it "should respond to #each" do
6
+ expect(subject).to respond_to(:each)
7
+ end
8
+
9
+ it "should be sorted properly" do
10
+ sorted_lessons = subject.sort
11
+ %w(1.3 2.5 5.8 10.2).each_with_index do |version, index|
12
+ expect(sorted_lessons[index].file_name).to eq "lesson#{version}.md"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,89 @@
1
+ RSpec.describe LessonsIndexer::Course do
2
+ subject {described_class.new('my_course_handouts', 'headings')}
3
+
4
+ specify "#dir" do
5
+ expect(subject.dir).to eq('my_course_handouts')
6
+ end
7
+
8
+ specify "#title" do
9
+ expect(subject.title).to eq('My Course')
10
+ end
11
+
12
+ specify "#headings_dir" do
13
+ expect(subject.headings_dir).to eq('headings')
14
+ end
15
+
16
+ specify "#headings" do
17
+ expect(subject.headings).to eq([])
18
+ end
19
+
20
+ specify "#generate_index" do
21
+ expect(subject).to receive(:lessons).and_return(sample_lessons)
22
+ expect(subject.generate_index).to eq("# Index for the My Course course\n\n* [Lesson 1.3](my_course_handouts/lesson1.3.md)\n* [Lesson 2.5](my_course_handouts/lesson2.5.md)\n* [Lesson 5.8](my_course_handouts/lesson5.8.md)\n* [Lesson 10.2](my_course_handouts/lesson10.2.md)\n")
23
+ end
24
+
25
+ context "#generate_headings" do
26
+ it "should return formatted heading and path to file" do
27
+ expect(subject).to receive(:lessons).and_return(sample_lessons)
28
+ expect(subject).to receive(:headings).and_return(sample_headings).exactly(4).times
29
+ expect {|block| subject.generate_headings(&block)}.to yield_successive_args(
30
+ ["![](headings/lesson2.5.jpg)\n\n", "#{Dir.pwd}/lesson2.5.md"],
31
+ ["![](headings/lesson10.2.jpg)\n\n", "#{Dir.pwd}/lesson10.2.md"],
32
+ ["![](headings/lesson1.3.jpg)\n\n", "#{Dir.pwd}/lesson1.3.md"],
33
+ ["![](headings/lesson5.8.jpg)\n\n", "#{Dir.pwd}/lesson5.8.md"]
34
+ )
35
+ end
36
+
37
+ it "should warn if heading is not found" do
38
+ expect(subject).to receive(:lessons).and_return(sample_lessons(true))
39
+ expect(subject).to receive(:headings).and_return(sample_headings).exactly(5).times
40
+ err = capture_stderr do
41
+ expect {|block| subject.generate_headings(&block)}.to yield_successive_args(
42
+ ["![](headings/lesson2.5.jpg)\n\n", "#{Dir.pwd}/lesson2.5.md"],
43
+ ["![](headings/lesson10.2.jpg)\n\n", "#{Dir.pwd}/lesson10.2.md"],
44
+ ["![](headings/lesson1.3.jpg)\n\n", "#{Dir.pwd}/lesson1.3.md"],
45
+ ["![](headings/lesson5.8.jpg)\n\n", "#{Dir.pwd}/lesson5.8.md"]
46
+ )
47
+ end.uncolorize
48
+ expect(err).to eq("[WARNING] I was not able to find heading image for the Lesson 6.3\n")
49
+ end
50
+ end
51
+
52
+ context "file system access" do
53
+ before(:all) { setup_env! }
54
+
55
+ after(:all) { clear_env! }
56
+
57
+ context "#load_headings!" do
58
+ let(:headings) {subject.load_headings!}
59
+
60
+ specify { expect(headings).to be_a LessonsIndexer::Collections::HeadingsList }
61
+
62
+ specify { expect(headings.map {|l| l.file_name}).not_to include('test2.png') }
63
+
64
+ it "should have four items" do
65
+ expect(headings.map {|l| l.file_name}.length).to eq(4)
66
+ end
67
+
68
+ specify "heading should be a kind of LessonsIndexer::Models::Heading" do
69
+ expect(headings.first).to be_a LessonsIndexer::Models::Heading
70
+ end
71
+ end
72
+
73
+ context "#load_lessons!" do
74
+ let(:lessons) {subject.load_lessons!}
75
+
76
+ specify { expect(lessons).to be_a LessonsIndexer::Collections::LessonsList }
77
+
78
+ specify { expect(lessons.map {|l| l.name}).not_to include('Test') }
79
+
80
+ it "should have four items" do
81
+ expect(lessons.map {|l| l.name}.length).to eq(4)
82
+ end
83
+
84
+ specify "lesson should be a kind of LessonsIndexer::Models::Lesson" do
85
+ expect(lessons.first).to be_a LessonsIndexer::Models::Lesson
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,83 @@
1
+ RSpec.describe LessonsIndexer::Indexer do
2
+ before(:all) { setup_env! }
3
+ after(:all) { clear_env! }
4
+
5
+ subject { described_class.new(LessonsIndexer::Options.new(sample_options)) }
6
+ let(:course) {LessonsIndexer::Course.new(subject.get_course_dir, subject.options.headings_dir)}
7
+
8
+ context "#options" do
9
+ it "should return output" do
10
+ expect(subject.options.output).to eq('test.md')
11
+ end
12
+ end
13
+
14
+ context "#do_work!" do
15
+ it "should build index if --skip_index is not set" do
16
+ expect(subject).to receive(:build_index)
17
+ expect(subject).not_to receive(:add_headings)
18
+ expect(subject).not_to receive(:git_push!)
19
+ capture_stdout { subject.do_work! }
20
+ end
21
+
22
+ it "should add headings if --headings is set" do
23
+ allow(subject.options).to receive(:skip_index).and_return(true)
24
+ allow(subject.options).to receive(:headings).and_return(true)
25
+ expect(subject).to receive(:add_headings)
26
+ expect(subject).not_to receive(:build_index)
27
+ expect(subject).not_to receive(:git_push!)
28
+ capture_stdout { subject.do_work! }
29
+ end
30
+
31
+ it "should push to github if --git is set" do
32
+ allow(subject.options).to receive(:skip_index).and_return(true)
33
+ allow(subject.options).to receive(:git).and_return(true)
34
+ expect(subject).to receive(:git_push!)
35
+ expect(subject).not_to receive(:build_index)
36
+ expect(subject).not_to receive(:add_headings)
37
+ capture_stdout { subject.do_work! }
38
+ end
39
+ end
40
+
41
+ context "#get_course_dir" do
42
+ it "should return course dir" do
43
+ expect(subject.get_course_dir)
44
+ end
45
+
46
+ it "should abort if course dir is not found" do
47
+ Kernel.within 'my_course_handouts', true do
48
+ err = capture_stderr do
49
+ expect(-> {subject.get_course_dir}).to raise_error(SystemExit)
50
+ end.uncolorize
51
+ expect(err).to eq("[ERROR] Lesson files were not found inside the provided directory. Aborting...\n")
52
+ end
53
+ end
54
+ end
55
+
56
+ context "#build_index" do
57
+ it "should display proper info messages" do
58
+ info = capture_stdout do
59
+ subject.build_index(course)
60
+ end.uncolorize
61
+ expect(info).to eq("Starting to build index...\nIndex for the My Course course is generated!\n#{'=' * 50}\n")
62
+ end
63
+
64
+ it "should generate proper index" do
65
+ capture_stdout { subject.build_index(course) }
66
+ expect(IO.read('test.md')).to eq("# Index for the My Course course\n\n* [Lesson 1.3](my_course_handouts/lesson1.3.md)\n* [Lesson 2.5](my_course_handouts/lesson2.5.md)\n* [Lesson 5.8](my_course_handouts/lesson5.8.md)\n* [Lesson 10.2](my_course_handouts/lesson10.2.md)\n")
67
+ end
68
+ end
69
+
70
+ context "#add_headings" do
71
+ it "should display proper info messages" do
72
+ info = capture_stdout do
73
+ subject.add_headings(course)
74
+ end.uncolorize
75
+ expect(info).to eq("Starting to add headings...\nHeadings for the lesson files of My Course course were added!\n#{'=' * 50}\n")
76
+ end
77
+
78
+ it "should generate proper index" do
79
+ capture_stdout { subject.add_headings(course) }
80
+ expect(IO.read('my_course_handouts/lesson10.2.md')).to eq("![](headings/lesson10.2.jpg)\n\n")
81
+ end
82
+ end
83
+ end