openstax_kitchen 4.1.1 → 8.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.
- checksums.yaml +4 -4
- data/.github/workflows/changelog.yml +24 -0
- data/.github/workflows/rubocop.yml +28 -0
- data/CHANGELOG.md +62 -0
- data/Gemfile.lock +16 -7
- data/docker/rubocop +24 -0
- data/lib/kitchen/composite_page_element.rb +20 -3
- data/lib/kitchen/directions/bake_appendix.rb +3 -1
- data/lib/kitchen/directions/bake_chapter_glossary/v1.rb +23 -5
- data/lib/kitchen/directions/bake_chapter_introductions.rb +22 -15
- data/lib/kitchen/directions/bake_chapter_introductions/chapter_introduction.xhtml.erb +0 -0
- data/lib/kitchen/directions/bake_chapter_references/main.rb +1 -2
- data/lib/kitchen/directions/bake_chapter_references/v1.rb +26 -12
- data/lib/kitchen/directions/bake_chapter_section_exercises/main.rb +2 -2
- data/lib/kitchen/directions/bake_chapter_section_exercises/v1.rb +2 -1
- data/lib/kitchen/directions/bake_chapter_solutions/main.rb +11 -0
- data/lib/kitchen/directions/bake_chapter_solutions/v1.rb +37 -0
- data/lib/kitchen/directions/bake_chapter_summary.rb +13 -6
- data/lib/kitchen/directions/bake_example.rb +11 -2
- data/lib/kitchen/directions/bake_figure.rb +13 -0
- data/lib/kitchen/directions/bake_first_elements.rb +7 -1
- data/lib/kitchen/directions/bake_footnotes/main.rb +2 -2
- data/lib/kitchen/directions/bake_footnotes/v1.rb +11 -8
- data/lib/kitchen/directions/bake_further_research.rb +2 -0
- data/lib/kitchen/directions/bake_index/v1.rb +3 -14
- data/lib/kitchen/directions/bake_inline_lists.rb +22 -0
- data/lib/kitchen/directions/bake_notes/bake_numbered_notes/main.rb +43 -0
- data/lib/kitchen/directions/bake_notes/bake_numbered_notes/v1.rb +37 -0
- data/lib/kitchen/directions/bake_notes/bake_numbered_notes/v2.rb +25 -0
- data/lib/kitchen/directions/bake_notes/bake_numbered_notes/v3.rb +32 -0
- data/lib/kitchen/directions/bake_numbered_exercise/main.rb +3 -2
- data/lib/kitchen/directions/bake_numbered_exercise/v1.rb +10 -1
- data/lib/kitchen/directions/bake_numbered_table/bake_table_body.rb +29 -0
- data/lib/kitchen/directions/bake_numbered_table/main.rb +4 -0
- data/lib/kitchen/directions/bake_numbered_table/v1.rb +1 -24
- data/lib/kitchen/directions/bake_numbered_table/v2.rb +31 -0
- data/lib/kitchen/directions/bake_preface/main.rb +2 -2
- data/lib/kitchen/directions/bake_preface/v1.rb +3 -2
- data/lib/kitchen/directions/bake_references/main.rb +7 -0
- data/lib/kitchen/directions/bake_references/v2.rb +35 -0
- data/lib/kitchen/directions/bake_toc.rb +3 -1
- data/lib/kitchen/directions/book_answer_key_container/eob_answer_key_outer_container.xhtml.erb +9 -0
- data/lib/kitchen/directions/book_answer_key_container/main.rb +2 -2
- data/lib/kitchen/directions/book_answer_key_container/v1.rb +4 -3
- data/lib/kitchen/directions/chapter_review_container/chapter_review.xhtml.erb +3 -3
- data/lib/kitchen/directions/chapter_review_container/main.rb +2 -2
- data/lib/kitchen/directions/chapter_review_container/v1.rb +4 -2
- data/lib/kitchen/directions/eoc_section_title_link_snippet.rb +13 -0
- data/lib/kitchen/directions/move_exercises_to_eoc/main.rb +10 -0
- data/lib/kitchen/directions/move_exercises_to_eoc/v3.rb +49 -0
- data/lib/kitchen/directions/move_solutions_to_answer_key/main.rb +6 -2
- data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/default.rb +27 -0
- data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/precalculus.rb +84 -0
- data/lib/kitchen/directions/move_solutions_to_answer_key/v1.rb +11 -7
- data/lib/kitchen/document.rb +17 -42
- data/lib/kitchen/element_base.rb +31 -7
- data/lib/kitchen/i18n_string.rb +16 -0
- data/lib/kitchen/id_tracker.rb +68 -0
- data/lib/kitchen/oven.rb +3 -1
- data/lib/kitchen/page_element.rb +2 -3
- data/lib/kitchen/patches/array.rb +15 -0
- data/lib/kitchen/patches/i18n.rb +34 -0
- data/lib/kitchen/patches/integer.rb +24 -0
- data/lib/kitchen/patches/nokogiri.rb +7 -0
- data/lib/kitchen/version.rb +1 -1
- data/lib/locales/en.yml +2 -1
- data/lib/locales/es.yml +33 -0
- data/lib/locales/pl.yml +3 -1
- data/lib/openstax_kitchen.rb +2 -5
- data/openstax_kitchen.gemspec +1 -0
- metadata +40 -7
- data/.github/config.yml +0 -14
- data/lib/kitchen/directions/bake_notes/bake_numbered_notes.rb +0 -51
- data/lib/kitchen/directions/book_answer_key_container/eob_solutions_container.xhtml.erb +0 -9
- data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/american_government.rb +0 -19
- data/lib/kitchen/transliterations.rb +0 -21
@@ -2,9 +2,10 @@
|
|
2
2
|
|
3
3
|
module Kitchen::Directions::BakeChapterSectionExercises
|
4
4
|
class V1
|
5
|
-
def bake(chapter:)
|
5
|
+
def bake(chapter:, trash_title:)
|
6
6
|
chapter.pages.each do |page|
|
7
7
|
page.search('section.section-exercises').each do |section|
|
8
|
+
section.first('h3[data-type="title"]')&.trash if trash_title
|
8
9
|
section.wrap(
|
9
10
|
%(<div class="os-eos os-section-exercises-container"
|
10
11
|
data-uuid-key=".section-exercises">)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeChapterSolutions
|
6
|
+
def self.v1(chapter:, metadata_source:, uuid_prefix: '')
|
7
|
+
V1.new.bake(chapter: chapter, metadata_source: metadata_source, uuid_prefix: uuid_prefix)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen::Directions::BakeChapterSolutions
|
4
|
+
class V1
|
5
|
+
renderable
|
6
|
+
|
7
|
+
def bake(chapter:, metadata_source:, uuid_prefix: '')
|
8
|
+
@metadata = metadata_source.children_to_keep.copy
|
9
|
+
@klass = 'solutions'
|
10
|
+
@title = I18n.t(:eoc_solutions_title)
|
11
|
+
@uuid_prefix = uuid_prefix
|
12
|
+
|
13
|
+
solutions_clipboard = Kitchen::Clipboard.new
|
14
|
+
|
15
|
+
chapter.search('section.free-response').each do |free_response_question|
|
16
|
+
exercises = free_response_question.exercises
|
17
|
+
# must run AFTER .free-response notes are baked
|
18
|
+
|
19
|
+
next if exercises.none?
|
20
|
+
|
21
|
+
exercises.each do |exercise|
|
22
|
+
solution = exercise.solution
|
23
|
+
next unless solution.present?
|
24
|
+
|
25
|
+
solution.cut(to: solutions_clipboard)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
@content = solutions_clipboard.paste
|
30
|
+
|
31
|
+
@in_composite_chapter = false
|
32
|
+
|
33
|
+
chapter.append(child: render(file:
|
34
|
+
'../../templates/eoc_section_title_template.xhtml.erb'))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -27,15 +27,22 @@ module Kitchen
|
|
27
27
|
# TODO: include specific page types somehow without writing it out
|
28
28
|
chapter.non_introduction_pages.each do |page|
|
29
29
|
summary = page.summary
|
30
|
+
|
31
|
+
next if summary.nil?
|
32
|
+
|
30
33
|
summary.first("[data-type='title']")&.trash # get rid of old title if exists
|
31
34
|
summary_title = page.title.copy
|
32
35
|
summary_title.name = 'h3'
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
|
37
|
+
unless summary_title.children.search('span.os-number').present?
|
38
|
+
summary_title.replace_children(with:
|
39
|
+
<<~HTML
|
40
|
+
<span class="os-number">#{chapter.count_in(:book)}.#{page.count_in(:chapter)}</span>
|
41
|
+
<span class="os-divider"> </span>
|
42
|
+
<span class="os-text" data-type="" itemprop="">#{summary_title.children}</span>
|
43
|
+
HTML
|
44
|
+
)
|
45
|
+
end
|
39
46
|
|
40
47
|
summary.prepend(child:
|
41
48
|
<<~HTML
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Kitchen
|
4
4
|
module Directions
|
5
5
|
module BakeExample
|
6
|
-
def self.v1(example:, number:, title_tag:)
|
6
|
+
def self.v1(example:, number:, title_tag:, numbered_solutions: false)
|
7
7
|
example.wrap_children(class: 'body')
|
8
8
|
|
9
9
|
example.prepend(child:
|
@@ -21,7 +21,10 @@ module Kitchen
|
|
21
21
|
.store("#{I18n.t(:example_label)} #{number}", label: example.id)
|
22
22
|
|
23
23
|
example.titles.each do |title|
|
24
|
-
|
24
|
+
if title.parent.has_class?('os-caption-container') || \
|
25
|
+
title.parent.has_class?('os-caption')
|
26
|
+
next
|
27
|
+
end
|
25
28
|
|
26
29
|
title.name = 'h4'
|
27
30
|
end
|
@@ -33,10 +36,16 @@ module Kitchen
|
|
33
36
|
end
|
34
37
|
|
35
38
|
if (solution = exercise.solution)
|
39
|
+
solution_number = if numbered_solutions
|
40
|
+
"<span class=\"os-number\">#{exercise.count_in(:example)}</span>"
|
41
|
+
else
|
42
|
+
''
|
43
|
+
end
|
36
44
|
solution.replace_children(with:
|
37
45
|
<<~HTML
|
38
46
|
<h4 data-type="solution-title">
|
39
47
|
<span class="os-title-label">#{I18n.t(:solution)} </span>
|
48
|
+
#{solution_number}
|
40
49
|
</h4>
|
41
50
|
<div class="os-solution-container">#{solution.children}</div>
|
42
51
|
HTML
|
@@ -4,7 +4,20 @@ module Kitchen
|
|
4
4
|
module Directions
|
5
5
|
module BakeFigure
|
6
6
|
def self.v1(figure:, number:)
|
7
|
+
return if figure.has_class?('unnumbered') && !figure.has_class?('splash')
|
8
|
+
|
7
9
|
figure.wrap(%(<div class="os-figure#{' has-splash' if figure.has_class?('splash')}">))
|
10
|
+
if figure.has_class?('unnumbered') && figure.has_class?('splash')
|
11
|
+
caption = figure.caption&.cut
|
12
|
+
figure.append(sibling:
|
13
|
+
<<~HTML
|
14
|
+
<div class="os-caption-container">
|
15
|
+
#{"<span class=\"os-caption\">#{caption.children}</span>" if caption}
|
16
|
+
</div>
|
17
|
+
HTML
|
18
|
+
)
|
19
|
+
return
|
20
|
+
end
|
8
21
|
|
9
22
|
figure.pantry(name: :link_text).store "#{I18n.t(:figure)} #{number}", label: figure.id
|
10
23
|
title = figure.title&.cut
|
@@ -3,7 +3,13 @@
|
|
3
3
|
module Kitchen
|
4
4
|
module Directions
|
5
5
|
module BakeFirstElements
|
6
|
-
def self.v1(within
|
6
|
+
def self.v1(within:)
|
7
|
+
selectors = [
|
8
|
+
'div.os-problem-container > div.os-table',
|
9
|
+
'div.os-problem-container > span[data-type="media"]',
|
10
|
+
'div.os-solution-container > div.os-table',
|
11
|
+
'div.os-solution-container > span[data-type="media"]'
|
12
|
+
]
|
7
13
|
selectors.each do |selector|
|
8
14
|
within.search("#{selector}:first-child").each do |problem|
|
9
15
|
problem.add_class('first-element')
|
@@ -3,37 +3,40 @@
|
|
3
3
|
module Kitchen::Directions::BakeFootnotes
|
4
4
|
class V1
|
5
5
|
|
6
|
-
def bake(book:)
|
6
|
+
def bake(book:, number_format: :arabic)
|
7
7
|
# Footnotes are numbered either within their top-level pages (preface,
|
8
8
|
# appendices, etc) or within chapters. Tackle each case separately
|
9
9
|
|
10
10
|
book.body.element_children.only(Kitchen::PageElement,
|
11
11
|
Kitchen::CompositePageElement,
|
12
12
|
Kitchen::CompositeChapterElement).each do |page|
|
13
|
-
bake_footnotes_within(page)
|
13
|
+
bake_footnotes_within(page, number_format: number_format)
|
14
14
|
end
|
15
15
|
|
16
16
|
book.chapters.each do |chapter|
|
17
|
-
bake_footnotes_within(chapter)
|
17
|
+
bake_footnotes_within(chapter, number_format: number_format)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
def bake_footnotes_within(container)
|
22
|
-
|
21
|
+
def bake_footnotes_within(container, number_format:)
|
22
|
+
footnote_count = 0
|
23
23
|
aside_id_to_footnote_number = {}
|
24
24
|
|
25
25
|
container.search("a[role='doc-noteref']").each do |anchor|
|
26
|
-
|
27
|
-
|
26
|
+
footnote_count += 1
|
27
|
+
footnote_number = footnote_count.to_format(number_format)
|
28
|
+
anchor.replace_children(with: footnote_number)
|
28
29
|
aside_id = anchor[:href][1..-1]
|
29
30
|
aside_id_to_footnote_number[aside_id] = footnote_number
|
31
|
+
anchor.parent.add_class('has-noteref') if anchor.parent.name == 'p'
|
30
32
|
end
|
31
33
|
|
32
34
|
container.search('aside').each do |aside|
|
33
35
|
footnote_number = aside_id_to_footnote_number[aside.id]
|
34
36
|
aside.prepend(child: "<div data-type='footnote-number'>#{footnote_number}</div>")
|
35
37
|
end
|
36
|
-
end
|
37
38
|
|
39
|
+
footnote_count
|
40
|
+
end
|
38
41
|
end
|
39
42
|
end
|
@@ -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'
|
@@ -27,13 +27,6 @@ module Kitchen::Directions::BakeIndex
|
|
27
27
|
def initialize(term_text:)
|
28
28
|
@term_text = term_text
|
29
29
|
@terms = []
|
30
|
-
|
31
|
-
# Sort by transliterated version first to support accent marks,
|
32
|
-
# then by the raw text to support the same text with different capitalization
|
33
|
-
@sortable = [
|
34
|
-
ActiveSupport::Inflector.transliterate(term_text).downcase,
|
35
|
-
term_text
|
36
|
-
]
|
37
30
|
end
|
38
31
|
|
39
32
|
def add_term(term)
|
@@ -49,12 +42,8 @@ module Kitchen::Directions::BakeIndex
|
|
49
42
|
end
|
50
43
|
|
51
44
|
def <=>(other)
|
52
|
-
|
45
|
+
I18n.sort_strings(term_text, other.term_text)
|
53
46
|
end
|
54
|
-
|
55
|
-
protected
|
56
|
-
|
57
|
-
attr_reader :sortable
|
58
47
|
end
|
59
48
|
|
60
49
|
class IndexSection
|
@@ -147,8 +136,8 @@ module Kitchen::Directions::BakeIndex
|
|
147
136
|
end
|
148
137
|
|
149
138
|
def add_term_to_index(term_element, page_title)
|
150
|
-
group_by = term_element.text.strip[0]
|
151
|
-
group_by = I18n.t(:eob_index_symbols_group) unless group_by.match?(
|
139
|
+
group_by = I18n.transliterate(term_element.text.strip[0])
|
140
|
+
group_by = I18n.t(:eob_index_symbols_group) unless group_by.match?(/[[:alpha:]]/)
|
152
141
|
term_element['group-by'] = group_by
|
153
142
|
|
154
143
|
# Add it to our index object
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
# Bakes inline lists with the desired list separator
|
6
|
+
# Does not separate the last list item
|
7
|
+
#
|
8
|
+
module BakeInlineLists
|
9
|
+
LIST_SEPARATOR = '; '
|
10
|
+
SEPARATOR_CLASS = '-os-inline-list-separator'
|
11
|
+
|
12
|
+
def self.v1(book:)
|
13
|
+
inline_lists = book.search('span[data-display="inline"][data-type="list"]')
|
14
|
+
inline_lists.each do |list|
|
15
|
+
list.search('span[data-type="item"]')[0..-2].each do |item|
|
16
|
+
item.append(child: "<span class=\"#{SEPARATOR_CLASS}\">#{LIST_SEPARATOR}</span>")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -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
|