openstax_kitchen 5.0.0 → 6.0.0

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