openstax_kitchen 5.0.0 → 6.0.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/changelog.yml +27 -0
  3. data/.github/workflows/rubocop.yml +28 -0
  4. data/CHANGELOG.md +33 -0
  5. data/Gemfile.lock +8 -6
  6. data/docker/rubocop +22 -0
  7. data/lib/kitchen/directions/bake_appendix.rb +3 -1
  8. data/lib/kitchen/directions/bake_chapter_introductions.rb +22 -15
  9. data/lib/kitchen/directions/bake_chapter_introductions/chapter_introduction.xhtml.erb +0 -0
  10. data/lib/kitchen/directions/bake_chapter_section_exercises/main.rb +2 -2
  11. data/lib/kitchen/directions/bake_chapter_section_exercises/v1.rb +2 -1
  12. data/lib/kitchen/directions/bake_chapter_solutions/main.rb +11 -0
  13. data/lib/kitchen/directions/bake_chapter_solutions/v1.rb +37 -0
  14. data/lib/kitchen/directions/bake_chapter_summary.rb +13 -6
  15. data/lib/kitchen/directions/bake_example.rb +4 -1
  16. data/lib/kitchen/directions/bake_figure.rb +13 -0
  17. data/lib/kitchen/directions/bake_footnotes/main.rb +2 -2
  18. data/lib/kitchen/directions/bake_footnotes/v1.rb +11 -8
  19. data/lib/kitchen/directions/bake_further_research.rb +2 -0
  20. data/lib/kitchen/directions/bake_index/v1.rb +2 -2
  21. data/lib/kitchen/directions/bake_notes/bake_numbered_notes/main.rb +43 -0
  22. data/lib/kitchen/directions/bake_notes/bake_numbered_notes/v1.rb +37 -0
  23. data/lib/kitchen/directions/bake_notes/bake_numbered_notes/v2.rb +25 -0
  24. data/lib/kitchen/directions/bake_notes/bake_numbered_notes/v3.rb +32 -0
  25. data/lib/kitchen/directions/bake_numbered_exercise/main.rb +3 -2
  26. data/lib/kitchen/directions/bake_numbered_exercise/v1.rb +10 -1
  27. data/lib/kitchen/directions/bake_numbered_table/bake_table_body.rb +29 -0
  28. data/lib/kitchen/directions/bake_numbered_table/main.rb +4 -0
  29. data/lib/kitchen/directions/bake_numbered_table/v1.rb +1 -17
  30. data/lib/kitchen/directions/bake_numbered_table/v2.rb +31 -0
  31. data/lib/kitchen/directions/bake_preface/main.rb +2 -2
  32. data/lib/kitchen/directions/bake_preface/v1.rb +3 -2
  33. data/lib/kitchen/directions/book_answer_key_container/eob_answer_key_outer_container.xhtml.erb +9 -0
  34. data/lib/kitchen/directions/book_answer_key_container/main.rb +2 -2
  35. data/lib/kitchen/directions/book_answer_key_container/v1.rb +4 -3
  36. data/lib/kitchen/directions/chapter_review_container/chapter_review.xhtml.erb +3 -3
  37. data/lib/kitchen/directions/chapter_review_container/main.rb +2 -2
  38. data/lib/kitchen/directions/chapter_review_container/v1.rb +4 -2
  39. data/lib/kitchen/directions/eoc_section_title_link_snippet.rb +13 -0
  40. data/lib/kitchen/directions/move_exercises_to_eoc/main.rb +10 -0
  41. data/lib/kitchen/directions/move_exercises_to_eoc/v3.rb +49 -0
  42. data/lib/kitchen/directions/move_solutions_to_answer_key/main.rb +6 -2
  43. data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/default.rb +27 -0
  44. data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/precalculus.rb +84 -0
  45. data/lib/kitchen/directions/move_solutions_to_answer_key/v1.rb +11 -7
  46. data/lib/kitchen/element_base.rb +15 -0
  47. data/lib/kitchen/page_element.rb +2 -3
  48. data/lib/kitchen/patches/integer.rb +24 -0
  49. data/lib/kitchen/patches/nokogiri.rb +7 -0
  50. data/lib/kitchen/version.rb +1 -1
  51. data/lib/locales/en.yml +2 -1
  52. data/lib/locales/es.yml +2 -1
  53. data/lib/locales/pl.yml +3 -2
  54. metadata +19 -6
  55. data/.github/config.yml +0 -14
  56. data/lib/kitchen/directions/bake_notes/bake_numbered_notes.rb +0 -51
  57. data/lib/kitchen/directions/book_answer_key_container/eob_solutions_container.xhtml.erb +0 -9
  58. data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/american_government.rb +0 -19
@@ -24,6 +24,8 @@ module Kitchen
24
24
 
25
25
  chapter.non_introduction_pages.each do |page|
26
26
  further_research = page.first('.further-research')
27
+ next unless further_research.present?
28
+
27
29
  further_research.first("[data-type='title']")&.trash # get rid of old title if exists
28
30
  further_research_title = page.title.copy
29
31
  further_research_title.name = 'h3'
@@ -136,8 +136,8 @@ module Kitchen::Directions::BakeIndex
136
136
  end
137
137
 
138
138
  def add_term_to_index(term_element, page_title)
139
- group_by = term_element.text.strip[0]
140
- group_by = I18n.t(:eob_index_symbols_group) unless group_by.match?(/\w/)
139
+ group_by = I18n.transliterate(term_element.text.strip[0])
140
+ group_by = I18n.t(:eob_index_symbols_group) unless group_by.match?(/[[:alpha:]]/)
141
141
  term_element['group-by'] = group_by
142
142
 
143
143
  # Add it to our index object
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeNumberedNotes
6
+ def self.v1(book:, classes:)
7
+ V1.new.bake(book: book, classes: classes)
8
+ end
9
+
10
+ def self.v2(book:, classes:)
11
+ V2.new.bake(book: book, classes: classes)
12
+ end
13
+
14
+ # V3 bakes notes tied to an example immediately previous ("Try It" notes)
15
+ # Must be called AFTER BakeExercises
16
+ #
17
+ def self.v3(book:, classes:, suppress_solution: true)
18
+ V3.new.bake(book: book, classes: classes, suppress_solution: suppress_solution)
19
+ end
20
+
21
+ # Used by V1, V2, V3
22
+ def self.bake_note_exercise(note:, exercise:, divider: ' ', suppress_solution: false)
23
+ exercise.add_class('unnumbered')
24
+ # bake problem
25
+ exercise.problem.wrap_children('div', class: 'os-problem-container')
26
+ exercise.search('[data-type="commentary"]').each(&:trash)
27
+ return unless exercise.solution
28
+
29
+ # bake solution in place
30
+ if suppress_solution
31
+ exercise.add_class('os-hasSolution')
32
+ exercise.solution.trash
33
+ else
34
+ BakeNumberedExercise.bake_solution_v1(
35
+ exercise: exercise,
36
+ number: note.first('.os-number').text.gsub(/#/, ''),
37
+ divider: divider
38
+ )
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeNumberedNotes
4
+
5
+ class V1
6
+ def bake(book:, classes:)
7
+ classes.each do |klass|
8
+ book.chapters.notes("$.#{klass}").each do |note|
9
+ bake_note(note: note)
10
+ note.exercises.each do |exercise|
11
+ Kitchen::Directions::BakeNumberedNotes.bake_note_exercise(note: note, exercise: exercise)
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ def bake_note(note:)
18
+ note.wrap_children(class: 'os-note-body')
19
+
20
+ chapter_count = note.ancestor(:chapter).count_in(:book)
21
+ note_count = note.count_in(:chapter)
22
+ note.prepend(child:
23
+ <<~HTML
24
+ <h3 class="os-title">
25
+ <span class="os-title-label">#{note.autogenerated_title}</span>
26
+ <span class="os-number">#{chapter_count}.#{note_count}</span>
27
+ <span class="os-divider"> </span>
28
+ </h3>
29
+ HTML
30
+ )
31
+
32
+ return unless note['use-subtitle']
33
+
34
+ Kitchen::Directions::BakeNoteSubtitle.v1(note: note)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeNumberedNotes
4
+ class V2
5
+ def bake(book:, classes:)
6
+ classes.each do |klass|
7
+ book.chapters.pages.notes("$.#{klass}").each do |note|
8
+ note.wrap_children(class: 'os-note-body')
9
+ note_count = note.count_in(:page)
10
+ note.prepend(child:
11
+ <<~HTML
12
+ <h3 class="os-title">
13
+ <span class="os-title-label">#{note.autogenerated_title}</span>
14
+ <span class="os-number">##{note_count}</span>
15
+ </h3>
16
+ HTML
17
+ )
18
+ note.exercises.each do |exercise|
19
+ Kitchen::Directions::BakeNumberedNotes.bake_note_exercise(note: note, exercise: exercise, divider: '. ')
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeNumberedNotes
4
+ class V3
5
+ # for the try it notes, must be called AFTER bake_exercises
6
+ def bake(book:, classes:, suppress_solution: true)
7
+ classes.each do |klass|
8
+ book.chapters.notes("$.#{klass}").each do |note|
9
+ note.wrap_children(class: 'os-note-body')
10
+ previous_example = note.previous
11
+ os_number = previous_example&.first('.os-number')&.children&.to_s
12
+
13
+ note.prepend(child:
14
+ <<~HTML
15
+ <h3 class="os-title">
16
+ <span class="os-title-label">#{note.autogenerated_title}</span>
17
+ <span class="os-number">#{os_number}</span>
18
+ </h3>
19
+ HTML
20
+ )
21
+
22
+ note.title&.trash
23
+ note.exercises.each do |exercise|
24
+ Kitchen::Directions::BakeNumberedNotes.bake_note_exercise(
25
+ note: note, exercise: exercise, divider: '. ', suppress_solution: suppress_solution
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -3,8 +3,9 @@
3
3
  module Kitchen
4
4
  module Directions
5
5
  module BakeNumberedExercise
6
- def self.v1(exercise:, number:, suppress_solution: false)
7
- V1.new.bake(exercise: exercise, number: number, suppress_solution: suppress_solution)
6
+ def self.v1(exercise:, number:, suppress_solution_if: false, note_suppressed_solutions: false)
7
+ V1.new.bake(exercise: exercise, number: number, suppress_solution_if: suppress_solution_if,
8
+ note_suppressed_solutions: note_suppressed_solutions)
8
9
  end
9
10
 
10
11
  def self.bake_solution_v1(exercise:, number:, divider: '. ')
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kitchen::Directions::BakeNumberedExercise
4
4
  class V1
5
- def bake(exercise:, number:, suppress_solution: false)
5
+ def bake(exercise:, number:, suppress_solution_if: false, note_suppressed_solutions: false)
6
6
  problem = exercise.problem
7
7
  solution = exercise.solution
8
8
 
@@ -12,9 +12,18 @@ module Kitchen::Directions::BakeNumberedExercise
12
12
  )
13
13
  problem_number = "<span class='os-number'>#{number}</span>"
14
14
 
15
+ suppress_solution =
16
+ case suppress_solution_if
17
+ when Symbol
18
+ number.send(suppress_solution_if)
19
+ else
20
+ suppress_solution_if
21
+ end
22
+
15
23
  if solution.present?
16
24
  if suppress_solution
17
25
  solution.trash
26
+ exercise.add_class('os-hasSolution-trashed') if note_suppressed_solutions
18
27
  else
19
28
  problem_number = "<a class='os-number' href='##{exercise.id}-solution'>#{number}</a>"
20
29
  bake_solution(exercise: exercise, number: number)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ # Bake directions for table body
6
+ #
7
+ module BakeTableBody
8
+ def self.v1(table:, number:)
9
+ table.remove_attribute('summary')
10
+ table.wrap(%(<div class="os-table">))
11
+
12
+ table_label = "#{I18n.t(:table_label)} #{number}"
13
+ table.pantry(name: :link_text).store table_label, label: table.id
14
+
15
+ if table.top_titled?
16
+ table.parent.add_class('os-top-titled-container')
17
+ table.prepend(sibling:
18
+ <<~HTML
19
+ <div class="os-table-title">#{table.title}</div>
20
+ HTML
21
+ )
22
+ table.title_row.trash
23
+ end
24
+
25
+ table.parent.add_class('os-column-header-container') if table.column_header?
26
+ end
27
+ end
28
+ end
29
+ end
@@ -6,6 +6,10 @@ module Kitchen
6
6
  def self.v1(table:, number:, always_caption: false)
7
7
  V1.new.bake(table: table, number: number, always_caption: always_caption)
8
8
  end
9
+
10
+ def self.v2(table:, number:)
11
+ V2.new.bake(table: table, number: number)
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -4,22 +4,7 @@ module Kitchen::Directions::BakeNumberedTable
4
4
  class V1
5
5
 
6
6
  def bake(table:, number:, always_caption: false)
7
- table.wrap(%(<div class="os-table">))
8
-
9
- table_label = "#{I18n.t(:table_label)} #{number}"
10
- table.pantry(name: :link_text).store table_label, label: table.id
11
-
12
- if table.top_titled?
13
- table.parent.add_class('os-top-titled-container')
14
- table.prepend(sibling:
15
- <<~HTML
16
- <div class="os-table-title">#{table.title}</div>
17
- HTML
18
- )
19
- table.title_row.trash
20
- end
21
-
22
- table.parent.add_class('os-column-header-container') if table.column_header?
7
+ Kitchen::Directions::BakeTableBody.v1(table: table, number: number)
23
8
 
24
9
  # TODO: extra spaces added here to match legacy implementation, but probably not meaningful?
25
10
  new_caption = ''
@@ -54,6 +39,5 @@ module Kitchen::Directions::BakeNumberedTable
54
39
  HTML
55
40
  )
56
41
  end
57
-
58
42
  end
59
43
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeNumberedTable
4
+ # Difference from v1: only in the caption
5
+ # V2 caption titles are nested within an .os-caption span
6
+ class V2
7
+
8
+ def bake(table:, number:)
9
+ Kitchen::Directions::BakeTableBody.v1(table: table, number: number)
10
+
11
+ caption = ''
12
+ if table&.caption&.first("span[data-type='title']")
13
+ caption_el = table.caption
14
+ caption_el.add_class('os-caption')
15
+ caption_el.name = 'span'
16
+ caption = caption_el.cut
17
+ end
18
+
19
+ table.append(sibling:
20
+ <<~HTML
21
+ <div class="os-caption-container">
22
+ <span class="os-title-label">#{I18n.t(:table_label)} </span>
23
+ <span class="os-number">#{number}</span>
24
+ <span class="os-divider"> </span>
25
+ #{caption}
26
+ </div>
27
+ HTML
28
+ )
29
+ end
30
+ end
31
+ end
@@ -3,8 +3,8 @@
3
3
  module Kitchen
4
4
  module Directions
5
5
  module BakePreface
6
- def self.v1(book:)
7
- V1.new.bake(book: book)
6
+ def self.v1(book:, title_element: 'h1')
7
+ V1.new.bake(book: book, title_element: title_element)
8
8
  end
9
9
  end
10
10
  end
@@ -2,15 +2,16 @@
2
2
 
3
3
  module Kitchen::Directions::BakePreface
4
4
  class V1
5
- def bake(book:)
5
+ def bake(book:, title_element:)
6
6
  book.pages('$.preface').each do |page|
7
+ page.search('div[data-type="description"], div[data-type="abstract"]').each(&:trash)
7
8
  page.titles.each do |title|
8
9
  title.replace_children(with:
9
10
  <<~HTML
10
11
  <span data-type="" itemprop="" class="os-text">#{title.text}</span>
11
12
  HTML
12
13
  )
13
- title.name = 'h1'
14
+ title.name = title_element
14
15
  end
15
16
  end
16
17
  end
@@ -0,0 +1,9 @@
1
+ <div class="os-eob os-<%= @solutions_or_solution %>-container" data-type="composite-chapter" data-uuid-key=".<%= @solutions_or_solution %>">
2
+ <h1 data-type="document-title">
3
+ <span class="os-text"><%= I18n.t(:answer_key_title) %></span>
4
+ </h1>
5
+ <div data-type="metadata" style="display: none;">
6
+ <h1 data-type="document-title" itemprop="name"><%= I18n.t(:answer_key_title) %></h1>
7
+ <%= @metadata.paste %>
8
+ </div>
9
+ </div>
@@ -3,8 +3,8 @@
3
3
  module Kitchen
4
4
  module Directions
5
5
  module BookAnswerKeyContainer
6
- def self.v1(book:)
7
- V1.new.bake(book: book)
6
+ def self.v1(book:, solutions_plural: true)
7
+ V1.new.bake(book: book, solutions_plural: solutions_plural)
8
8
  end
9
9
  end
10
10
  end
@@ -4,10 +4,11 @@ module Kitchen::Directions::BookAnswerKeyContainer
4
4
  class V1
5
5
  renderable
6
6
 
7
- def bake(book:)
7
+ def bake(book:, solutions_plural: true)
8
8
  @metadata = book.metadata.children_to_keep.copy
9
- book.body.append(child: render(file: 'eob_solutions_container.xhtml.erb'))
10
- book.body.first('div.os-eob.os-solutions-container')
9
+ @solutions_or_solution = solutions_plural ? 'solutions' : 'solution'
10
+ book.body.append(child: render(file: 'eob_answer_key_outer_container.xhtml.erb'))
11
+ book.body.first("div.os-eob.os-#{@solutions_or_solution}-container")
11
12
  end
12
13
  end
13
14
  end
@@ -1,9 +1,9 @@
1
- <div class="os-eoc os-chapter-review-container" data-type="composite-chapter" data-uuid-key=".chapter-review">
1
+ <div class="os-eoc os-<%= @klass %>-container" data-type="composite-chapter" data-uuid-key=".<%= @klass %>">
2
2
  <h2 data-type="document-title">
3
- <span class="os-text"><%= I18n.t(:eoc_chapter_review) %></span>
3
+ <span class="os-text"><%= @title %></span>
4
4
  </h2>
5
5
  <div data-type="metadata" style="display: none;">
6
- <h1 data-type="document-title" itemprop="name"><%= I18n.t(:eoc_chapter_review) %></h1>
6
+ <h1 data-type="document-title" itemprop="name"><%= @title %></h1>
7
7
  <%= @metadata.paste %>
8
8
  </div>
9
9
  </div>
@@ -3,8 +3,8 @@
3
3
  module Kitchen
4
4
  module Directions
5
5
  module ChapterReviewContainer
6
- def self.v1(chapter:, metadata_source:)
7
- V1.new.bake(chapter: chapter, metadata_source: metadata_source)
6
+ def self.v1(chapter:, metadata_source:, klass: 'chapter-review')
7
+ V1.new.bake(chapter: chapter, metadata_source: metadata_source, klass: klass)
8
8
  end
9
9
  end
10
10
  end
@@ -4,10 +4,12 @@ module Kitchen::Directions::ChapterReviewContainer
4
4
  class V1
5
5
  renderable
6
6
 
7
- def bake(chapter:, metadata_source:)
7
+ def bake(chapter:, metadata_source:, klass: 'chapter-review')
8
8
  @metadata = metadata_source.children_to_keep.copy
9
+ @klass = klass
10
+ @title = I18n.t(:"eoc.#{klass}")
9
11
  chapter.append(child: render(file: 'chapter_review.xhtml.erb'))
10
- chapter.first('div.os-eoc.os-chapter-review-container')
12
+ chapter.element_children[-1]
11
13
  end
12
14
  end
13
15
  end
@@ -15,6 +15,19 @@ module Kitchen
15
15
  </a>
16
16
  HTML
17
17
  end
18
+
19
+ def self.v2(page:)
20
+ chapter = page.ancestor(:chapter)
21
+ <<~HTML
22
+ <div>
23
+ <h3 data-type="document-title" id="#{page.title.copied_id}">
24
+ <span class="os-number">#{chapter.count_in(:book)}.#{page.count_in(:chapter)}</span>
25
+ <span class="os-divider"> </span>
26
+ <span class="os-text" data-type="" itemprop="">#{page.title_text}</span>
27
+ </h3>
28
+ </div>
29
+ HTML
30
+ end
18
31
  end
19
32
  end
20
33
  end