openstax_kitchen 3.0.0 → 3.1.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -3
  3. data/Gemfile.lock +1 -1
  4. data/README.md +7 -0
  5. data/lib/kitchen/directions/bake_book_answer_key/eob_solutions_container.xhtml.erb +9 -0
  6. data/lib/kitchen/directions/bake_book_answer_key/main.rb +11 -0
  7. data/lib/kitchen/directions/bake_book_answer_key/v1.rb +13 -0
  8. data/lib/kitchen/directions/bake_chapter_answer_key/main.rb +14 -0
  9. data/lib/kitchen/directions/bake_chapter_answer_key/strategies/calculus.rb +41 -0
  10. data/lib/kitchen/directions/bake_chapter_answer_key/strategies/uphysics.rb +61 -0
  11. data/lib/kitchen/directions/bake_chapter_answer_key/v1.rb +32 -0
  12. data/lib/kitchen/directions/bake_chapter_glossary.rb +4 -2
  13. data/lib/kitchen/directions/bake_chapter_key_concepts/key_concepts.xhtml.erb +16 -0
  14. data/lib/kitchen/directions/bake_chapter_key_concepts/main.rb +11 -0
  15. data/lib/kitchen/directions/bake_chapter_key_concepts/v1.rb +30 -0
  16. data/lib/kitchen/directions/bake_chapter_key_equations.rb +4 -2
  17. data/lib/kitchen/directions/bake_chapter_review/chapter_review.xhtml.erb +9 -0
  18. data/lib/kitchen/directions/bake_chapter_review/main.rb +11 -0
  19. data/lib/kitchen/directions/bake_chapter_review/v1.rb +13 -0
  20. data/lib/kitchen/directions/bake_chapter_review_exercises/main.rb +15 -0
  21. data/lib/kitchen/directions/bake_chapter_review_exercises/review_exercises.xhtml.erb +10 -0
  22. data/lib/kitchen/directions/bake_chapter_review_exercises/v1.rb +38 -0
  23. data/lib/kitchen/directions/bake_chapter_review_exercises/v2.rb +50 -0
  24. data/lib/kitchen/directions/bake_chapter_section_exercises/main.rb +11 -0
  25. data/lib/kitchen/directions/bake_chapter_section_exercises/v1.rb +28 -0
  26. data/lib/kitchen/directions/bake_chapter_summary.rb +1 -1
  27. data/lib/kitchen/directions/bake_checkpoint.rb +44 -0
  28. data/lib/kitchen/directions/bake_composite_chapters.rb +14 -0
  29. data/lib/kitchen/directions/bake_equations.rb +27 -0
  30. data/lib/kitchen/directions/bake_example.rb +29 -7
  31. data/lib/kitchen/directions/bake_exercises/main.rb +1 -0
  32. data/lib/kitchen/directions/bake_exercises/v1.rb +34 -31
  33. data/lib/kitchen/directions/bake_non_introduction_pages.rb +26 -0
  34. data/lib/kitchen/directions/bake_notes/bake_autotitled_notes.rb +29 -0
  35. data/lib/kitchen/directions/bake_notes/bake_note_subtitle.rb +18 -0
  36. data/lib/kitchen/directions/{bake_notes.rb → bake_notes/bake_notes.rb} +6 -16
  37. data/lib/kitchen/directions/bake_notes/bake_numbered_notes.rb +63 -0
  38. data/lib/kitchen/directions/bake_notes/bake_unclassified_notes.rb +30 -0
  39. data/lib/kitchen/directions/bake_numbered_exercise/main.rb +11 -0
  40. data/lib/kitchen/directions/bake_numbered_exercise/v1.rb +34 -0
  41. data/lib/kitchen/directions/bake_numbered_table/main.rb +2 -2
  42. data/lib/kitchen/directions/bake_numbered_table/v1.rb +17 -3
  43. data/lib/kitchen/directions/bake_page_abstracts.rb +16 -0
  44. data/lib/kitchen/directions/bake_problem_first_elements.rb +16 -0
  45. data/lib/kitchen/directions/bake_stepwise.rb +1 -5
  46. data/lib/kitchen/directions/bake_theorem/main.rb +11 -0
  47. data/lib/kitchen/directions/bake_theorem/v1.rb +28 -0
  48. data/lib/kitchen/directions/bake_toc.rb +6 -0
  49. data/lib/kitchen/directions/eoc_section_title_link_snippet.rb +20 -0
  50. data/lib/kitchen/element_base.rb +40 -1
  51. data/lib/kitchen/element_enumerator_base.rb +87 -8
  52. data/lib/kitchen/exercise_element.rb +45 -0
  53. data/lib/kitchen/exercise_element_enumerator.rb +21 -0
  54. data/lib/kitchen/note_element.rb +17 -16
  55. data/lib/kitchen/page_element.rb +8 -0
  56. data/lib/kitchen/recipe.rb +35 -2
  57. data/lib/kitchen/version.rb +1 -1
  58. data/lib/locales/en.yml +9 -7
  59. data/lib/locales/pl.yml +24 -0
  60. data/lib/openstax_kitchen.rb +1 -1
  61. metadata +39 -3
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeChapterReviewExercises
4
+ class V1
5
+ renderable
6
+
7
+ def bake(chapter:, metadata_source:, append_to:, klass:)
8
+ @klass = klass
9
+ @metadata = metadata_source.children_to_keep.copy
10
+ @title = I18n.t(:"eoc.#{klass}")
11
+
12
+ exercise_clipboard = Kitchen::Clipboard.new
13
+
14
+ chapter.non_introduction_pages.each do |page|
15
+ sections = page.search("section.#{@klass}")
16
+
17
+ sections.each do |exercise_section|
18
+ exercise_section.first("[data-type='title']")&.trash
19
+
20
+ exercise_section.exercises.each do |exercise|
21
+ exercise.document.pantry(name: :link_text).store(
22
+ "#{I18n.t(:exercise_label)} #{chapter.count_in(:book)}.#{exercise.count_in(:chapter)}",
23
+ label: exercise.id
24
+ )
25
+ end
26
+
27
+ exercise_section.cut(to: exercise_clipboard)
28
+ end
29
+ end
30
+
31
+ return if exercise_clipboard.none?
32
+
33
+ @content = exercise_clipboard.paste
34
+
35
+ append_to.append(child: render(file: 'review_exercises.xhtml.erb'))
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeChapterReviewExercises
4
+ # Main difference from v1 is the presence of a section title
5
+ # and some additional wrappers
6
+ class V2
7
+ renderable
8
+
9
+ def bake(chapter:, metadata_source:, append_to:, klass:)
10
+ @klass = klass
11
+ @metadata = metadata_source.children_to_keep.copy
12
+ @title = I18n.t(:"eoc.#{klass}")
13
+
14
+ exercise_clipboard = Kitchen::Clipboard.new
15
+
16
+ chapter.non_introduction_pages.each do |page|
17
+ sections = page.search("section.#{@klass}")
18
+
19
+ sections.each do |exercise_section|
20
+ exercise_section.first("[data-type='title']")&.trash
21
+
22
+ # Get parent page title
23
+ section_title = Kitchen::Directions::EocSectionTitleLinkSnippet.v1(page: page)
24
+ exercise_section.exercises.each do |exercise|
25
+ exercise.document.pantry(name: :link_text).store(
26
+ "#{I18n.t(:exercise_label)} #{chapter.count_in(:book)}.#{exercise.count_in(:chapter)}",
27
+ label: exercise.id
28
+ )
29
+ end
30
+
31
+ # Configure section title & wrappers
32
+ exercise_section.prepend(child: section_title)
33
+ exercise_section.wrap('<div class="os-section-area">')
34
+ exercise_section = exercise_section.parent
35
+ exercise_section.cut(to: exercise_clipboard)
36
+ end
37
+ end
38
+
39
+ return if exercise_clipboard.none?
40
+
41
+ @content = <<~HTML
42
+ <div class="os-#{@klass}">
43
+ #{exercise_clipboard.paste}
44
+ </div>
45
+ HTML
46
+
47
+ append_to.append(child: render(file: 'review_exercises.xhtml.erb'))
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeChapterSectionExercises
6
+ def self.v1(chapter:)
7
+ V1.new.bake(chapter: chapter)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeChapterSectionExercises
4
+ class V1
5
+ def bake(chapter:)
6
+ chapter.pages.each do |page|
7
+ page.search('section.section-exercises').each do |section|
8
+ section.wrap(
9
+ %(<div class="os-eos os-section-exercises-container"
10
+ data-uuid-key=".section-exercises">)
11
+ )
12
+
13
+ section_title = I18n.t(
14
+ :section_exercises,
15
+ number: "#{chapter.count_in(:book)}.#{section.count_in(:chapter)}")
16
+
17
+ section.prepend(sibling:
18
+ <<~HTML
19
+ <h3 data-type="document-title">
20
+ <span class="os-text">#{section_title}</span>
21
+ </h3>
22
+ HTML
23
+ )
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -11,7 +11,7 @@ module Kitchen
11
11
  summaries = Clipboard.new
12
12
 
13
13
  # TODO: include specific page types somehow without writing it out
14
- chapter.pages('$:not(.introduction)').each do |page|
14
+ chapter.non_introduction_pages.each do |page|
15
15
  summary = page.summary
16
16
  summary.first("[data-type='title']")&.trash # get rid of old title if exists
17
17
  summary_title = page.title.copy
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeCheckpoint
6
+ def self.v1(checkpoint:, number:)
7
+ checkpoint.wrap_children(class: 'os-note-body')
8
+
9
+ checkpoint.prepend(child:
10
+ <<~HTML
11
+ <div class="os-title">
12
+ <span class="os-title-label">#{I18n.t(:checkpoint)} </span>
13
+ <span class="os-number">#{number}</span>
14
+ <span class="os-divider"> </span>
15
+ </div>
16
+ HTML
17
+ )
18
+
19
+ exercise = checkpoint.exercises.first!
20
+ exercise.search("[data-type='commentary']").trash
21
+
22
+ problem = exercise.problem
23
+ problem.wrap_children(class: 'os-problem-container')
24
+
25
+ solution = exercise.solution
26
+ exercise.add_class('unnumbered') unless solution.present?
27
+ return unless solution.present?
28
+
29
+ solution.id = "#{exercise.id}-solution"
30
+ exercise.add_class('os-hasSolution')
31
+
32
+ solution.replace_children(with:
33
+ <<~HTML
34
+ <span class="os-divider"> </span>
35
+ <a class="os-number" href="##{exercise.id}">#{number}</a>
36
+ <div class="os-solution-container">#{solution.children}</div>
37
+ HTML
38
+ )
39
+
40
+ exercise.add_class('unnumbered')
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeCompositeChapters
6
+ def self.v1(book:)
7
+ book.search("[data-type='composite-chapter']").each do |chapter|
8
+ chapter.first("[data-type='document-title']").id =
9
+ "composite-chapter-#{chapter.count_in(:book)}"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeEquations
6
+ def self.v1(book:)
7
+ book.chapters.search('[data-type="equation"]:not(.unnumbered)').each do |eq|
8
+ chapter = eq.ancestor(:chapter)
9
+ number = "#{chapter.count_in(:book)}.#{eq.count_in(:chapter)}"
10
+
11
+ # Store label information
12
+ equation_label = "#{I18n.t(:equation)} #{number}"
13
+ book.document.pantry(name: :link_text).store equation_label, label: eq.id
14
+
15
+ # Bake the equation
16
+ eq.append(child:
17
+ <<~HTML
18
+ <div class="os-equation-number">
19
+ <span class="os-number">#{number}</span>
20
+ </div>
21
+ HTML
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -4,13 +4,7 @@ module Kitchen
4
4
  module Directions
5
5
  module BakeExample
6
6
  def self.v1(example:, number:, title_tag:)
7
- example.replace_children(with:
8
- <<~HTML
9
- <div class="body">
10
- #{example.children}
11
- </div>
12
- HTML
13
- )
7
+ example.wrap_children(class: 'body')
14
8
 
15
9
  example.prepend(child:
16
10
  <<~HTML
@@ -27,6 +21,34 @@ module Kitchen
27
21
  .store("#{I18n.t(:example_label)} #{number}", label: example.id)
28
22
 
29
23
  example.titles.each { |title| title.name = 'h4' }
24
+
25
+ example.exercises.each do |exercise|
26
+ if (problem = exercise.problem)
27
+ problem.titles.each { |title| title.name = 'h4' }
28
+ problem.wrap_children(class: 'os-problem-container')
29
+ end
30
+
31
+ if (solution = exercise.solution)
32
+ solution.replace_children(with:
33
+ <<~HTML
34
+ <h4 data-type="solution-title">
35
+ <span class="os-title-label">#{I18n.t(:solution)} </span>
36
+ </h4>
37
+ <div class="os-solution-container">#{solution.children}</div>
38
+ HTML
39
+ )
40
+ end
41
+
42
+ exercise.add_class('unnumbered')
43
+
44
+ commentary = exercise.first('[data-type="commentary"]')
45
+ next unless commentary.present?
46
+
47
+ commentary_title = commentary.titles.first
48
+ commentary_title.name = 'h4'
49
+ commentary_title['data-type'] = 'commentary-title'
50
+ commentary_title.wrap_children('span', class: 'os-title-label')
51
+ end
30
52
  end
31
53
  end
32
54
  end
@@ -4,6 +4,7 @@ module Kitchen
4
4
  module Directions
5
5
  module BakeExercises
6
6
  def self.v1(book:)
7
+ warn 'WARNING! deprecated direction used: BakeExecises'
7
8
  V1.new.bake(book: book)
8
9
  end
9
10
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Kitchen::Directions::BakeExercises
4
4
  class V1
5
+ renderable
5
6
  def bake(book:)
6
7
  metadata_elements = book.metadata.children_to_keep.copy
7
8
 
@@ -12,34 +13,20 @@ module Kitchen::Directions::BakeExercises
12
13
  solution_clipboard = Kitchen::Clipboard.new
13
14
  solutions_clipboards.push(solution_clipboard)
14
15
 
15
- chapter.pages('$:not(.introduction)').each do |page|
16
+ chapter.non_introduction_pages.each do |page|
16
17
  exercise_section = page.exercises
17
- exercise_section.first("[data-type='title']")&.trash
18
- exercise_section_title = page.title.copy
19
- exercise_section_title.name = 'h3'
20
- exercise_section_title.replace_children(with: <<~HTML
21
- <span class="os-number">#{chapter.count_in(:book)}.#{page.count_in(:chapter)}</span>
22
- <span class="os-divider"> </span>
23
- <span class="os-text" data-type="" itemprop="">#{exercise_section_title.children}</span>
24
- HTML
25
- )
18
+ exercise_section.titles.first&.trash
26
19
 
27
- exercise_section.prepend(child:
28
- <<~HTML
29
- <a href="##{page.title.id}">
30
- #{exercise_section_title.paste}
31
- </a>
32
- HTML
33
- )
20
+ bake_exercise_section_title(
21
+ exercise_section: exercise_section, page: page, chapter: chapter)
34
22
 
35
- exercise_section.search("[data-type='exercise']").each do |exercise|
23
+ exercise_section.exercises.each do |exercise|
36
24
  exercise.document.pantry(name: :link_text).store(
37
25
  "#{I18n.t(:exercise_label)} #{chapter.count_in(:book)}.#{exercise.count_in(:chapter)}",
38
26
  label: exercise.id
39
27
  )
40
-
41
28
  bake_exercise_in_place(exercise: exercise)
42
- exercise.first("[data-type='solution']")&.cut(to: solution_clipboard)
29
+ exercise.solution&.cut(to: solution_clipboard)
43
30
  end
44
31
 
45
32
  exercise_section.cut(to: exercise_clipboard)
@@ -65,10 +52,9 @@ module Kitchen::Directions::BakeExercises
65
52
 
66
53
  # Store a paste here to use at end so that uniquifyied IDs match legacy baking
67
54
  eob_metadata = metadata_elements.paste
68
-
69
55
  solutions = solutions_clipboards.map.with_index do |solution_clipboard, index|
70
56
  <<~HTML
71
- <div class="os-eob os-solution-container " data-type="composite-page" data-uuid-key=".solution#{index + 1}">
57
+ <div class="os-eob os-solution-container" data-type="composite-page" data-uuid-key=".solution#{index + 1}">
72
58
  <h2 data-type="document-title">
73
59
  <span class="os-text">#{I18n.t(:chapter)} #{index + 1}</span>
74
60
  </h2>
@@ -83,9 +69,9 @@ module Kitchen::Directions::BakeExercises
83
69
 
84
70
  return if solutions.none?
85
71
 
86
- book.first('body').append(child:
72
+ book.body.append(child:
87
73
  <<~HTML
88
- <div class="os-eob os-solution-container " data-type="composite-chapter" data-uuid-key=".solution">
74
+ <div class="os-eob os-solution-container" data-type="composite-chapter" data-uuid-key=".solution">
89
75
  <h1 data-type="document-title" id="composite-chapter-1">
90
76
  <span class="os-text">#{I18n.t(:eoc_answer_key_title)}</span>
91
77
  </h1>
@@ -99,6 +85,24 @@ module Kitchen::Directions::BakeExercises
99
85
  )
100
86
  end
101
87
 
88
+ def bake_exercise_section_title(exercise_section:, chapter:, page:)
89
+ exercise_section_title = page.title.copy
90
+ exercise_section_title.name = 'h3'
91
+ exercise_section_title.replace_children(with: <<~HTML
92
+ <span class="os-number">#{chapter.count_in(:book)}.#{page.count_in(:chapter)}</span>
93
+ <span class="os-divider"> </span>
94
+ <span class="os-text" data-type="" itemprop="">#{exercise_section_title.children}</span>
95
+ HTML
96
+ )
97
+ exercise_section.prepend(child:
98
+ <<~HTML
99
+ <a href="##{page.title.id}">
100
+ #{exercise_section_title.paste}
101
+ </a>
102
+ HTML
103
+ )
104
+ end
105
+
102
106
  def bake_exercise_in_place(exercise:)
103
107
  # Bake an exercise in place going from:
104
108
  #
@@ -133,21 +137,20 @@ module Kitchen::Directions::BakeExercises
133
137
  # If there is no solution, don't add the 'os-hasSolution' class and don't
134
138
  # link the number.
135
139
 
136
- problem = exercise.first("[data-type='problem']")
137
- solution = exercise.first("[data-type='solution']")
138
-
139
- problem_number = "<span class='os-number'>#{exercise.count_in(:chapter)}</span>"
140
+ problem = exercise.problem
141
+ solution = exercise.solution
142
+ count_in = exercise.count_in(:chapter)
143
+ problem_number = "<span class='os-number'>#{count_in}</span>"
140
144
 
141
145
  if solution.present?
142
146
  solution.id = "#{exercise.id}-solution"
143
147
 
144
148
  exercise.add_class('os-hasSolution')
145
- problem_number =
146
- "<a href='##{solution.id}' class='os-number' >#{exercise.count_in(:chapter)}</a>"
149
+ problem_number = "<a href='##{solution.id}' class='os-number'>#{count_in}</a>"
147
150
 
148
151
  solution.replace_children(with:
149
152
  <<~HTML
150
- <a class="os-number" href="##{exercise.id}">#{exercise.count_in(:chapter)}</a>
153
+ <a class="os-number" href="##{exercise.id}">#{count_in}</a>
151
154
  <span class="os-divider">. </span>
152
155
  <div class="os-solution-container ">#{solution.children}</div>
153
156
  HTML
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeNonIntroductionPages
6
+ def self.v1(chapter:)
7
+ chapter.non_introduction_pages.each do |page|
8
+ number = "#{chapter.count_in(:book)}.#{page.count_in(:chapter)}"
9
+
10
+ page.search("div[data-type='description']").each(&:trash)
11
+ page.add_class('chapter-content-module')
12
+
13
+ title = page.title
14
+ title.name = 'h2'
15
+ title.replace_children(with:
16
+ <<~HTML
17
+ <span class="os-number">#{number}</span>
18
+ <span class="os-divider"> </span>
19
+ <span data-type="" itemprop="" class="os-text">#{title.text}</span>
20
+ HTML
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeAutotitledNotes
6
+ def self.v1(book:, classes:)
7
+ book.notes.each do |note|
8
+ next unless (note.classes & classes).any?
9
+
10
+ bake_note(note: note)
11
+ end
12
+ end
13
+
14
+ def self.bake_note(note:)
15
+ note.wrap_children(class: 'os-note-body')
16
+
17
+ BakeNoteSubtitle.v1(note: note)
18
+
19
+ note.prepend(child:
20
+ <<~HTML
21
+ <h3 class="os-title" data-type="title">
22
+ <span class="os-title-label">#{note.autogenerated_title}</span>
23
+ </h3>
24
+ HTML
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end