openstax_kitchen 4.1.1 → 8.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen::Directions::MoveSolutionsToAnswerKey
|
4
|
+
module Strategies
|
5
|
+
class Default
|
6
|
+
def bake(chapter:, append_to:)
|
7
|
+
bake_section(chapter: chapter, append_to: append_to)
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def bake_section(chapter:, append_to:)
|
13
|
+
@selectors.each do |selector|
|
14
|
+
chapter.search("#{selector} div[data-type='solution']").each do |solution|
|
15
|
+
append_to.add_child(solution.cut.to_s)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# This method helps to obtain more strategy-specific params through
|
21
|
+
# "strategy_options: {blah1: 1, blah2: 2}"
|
22
|
+
def initialize(strategy_options)
|
23
|
+
@selectors = strategy_options[:selectors] || (raise 'missing selectors for strategy')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen::Directions::MoveSolutionsToAnswerKey
|
4
|
+
module Strategies
|
5
|
+
class Precalculus
|
6
|
+
def bake(chapter:, append_to:)
|
7
|
+
try_note_solutions(chapter: chapter, append_to: append_to)
|
8
|
+
|
9
|
+
# Bake section exercises
|
10
|
+
chapter.non_introduction_pages.each do |page|
|
11
|
+
number = "#{chapter.count_in(:book)}.#{page.count_in(:chapter)}"
|
12
|
+
bake_section(chapter: page, append_to: append_to, klass: 'section-exercises',
|
13
|
+
number: number)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Bake other types of exercises
|
17
|
+
classes = %w[review-exercises practice-test]
|
18
|
+
classes.each do |klass|
|
19
|
+
bake_section(chapter: chapter, append_to: append_to, klass: klass)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def bake_section(chapter:, append_to:, klass:, number: nil)
|
26
|
+
section_solutions_set = Kitchen::Clipboard.new
|
27
|
+
chapter.search(".#{klass}").each do |section|
|
28
|
+
section.search('[data-type="solution"]').each do |solution|
|
29
|
+
solution.cut(to: section_solutions_set)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
return if section_solutions_set.items.empty?
|
34
|
+
|
35
|
+
title = <<~HTML
|
36
|
+
<h3 data-type="title">
|
37
|
+
<span class="os-title-label">#{I18n.t(:"eoc.#{klass}", number: number)}</span>
|
38
|
+
</h3>
|
39
|
+
HTML
|
40
|
+
|
41
|
+
append_solution_area(title: title, solutions: section_solutions_set, append_to: append_to)
|
42
|
+
end
|
43
|
+
|
44
|
+
def try_note_solutions(chapter:, append_to:)
|
45
|
+
append_to.add_child(
|
46
|
+
<<~HTML
|
47
|
+
<div class="os-module-reset-solution-area os-try-solution-area">
|
48
|
+
<h3 data-type="title">
|
49
|
+
<span class="os-title-label">#{I18n.t(:"notes.try")}</span>
|
50
|
+
</h3>
|
51
|
+
</div>
|
52
|
+
HTML
|
53
|
+
)
|
54
|
+
chapter.non_introduction_pages.each do |page|
|
55
|
+
solutions = Kitchen::Clipboard.new
|
56
|
+
page.notes('$.try').each do |note|
|
57
|
+
note.exercises.each do |exercise|
|
58
|
+
solution = exercise.solution
|
59
|
+
solution&.cut(to: solutions) #if solution
|
60
|
+
end
|
61
|
+
end
|
62
|
+
next if solutions.items.empty?
|
63
|
+
|
64
|
+
title_snippet = Kitchen::Directions::EocSectionTitleLinkSnippet.v2(page: page)
|
65
|
+
|
66
|
+
append_solution_area(title: title_snippet, solutions: solutions,
|
67
|
+
append_to: append_to.search('.os-try-solution-area').first)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def append_solution_area(title:, solutions:, append_to:)
|
72
|
+
append_to = append_to.add_child(
|
73
|
+
<<~HTML
|
74
|
+
<div class="os-solution-area">
|
75
|
+
#{title}
|
76
|
+
</div>
|
77
|
+
HTML
|
78
|
+
).first
|
79
|
+
|
80
|
+
append_to.add_child(solutions.paste)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -2,22 +2,26 @@
|
|
2
2
|
|
3
3
|
module Kitchen::Directions::MoveSolutionsToAnswerKey
|
4
4
|
class V1
|
5
|
-
def bake(chapter:, metadata_source:, strategy:, append_to:)
|
5
|
+
def bake(chapter:, metadata_source:, strategy:, append_to:, strategy_options: {}, solutions_plural: true)
|
6
6
|
strategy =
|
7
7
|
case strategy
|
8
8
|
when :calculus
|
9
|
-
Strategies::Calculus
|
9
|
+
Strategies::Calculus.new
|
10
10
|
when :uphysics
|
11
|
-
Strategies::UPhysics
|
12
|
-
when :
|
13
|
-
Strategies::
|
11
|
+
Strategies::UPhysics.new
|
12
|
+
when :precalculus
|
13
|
+
Strategies::Precalculus.new
|
14
|
+
when :default
|
15
|
+
Strategies::Default.new(strategy_options)
|
14
16
|
else
|
15
17
|
raise 'No such strategy'
|
16
18
|
end
|
17
19
|
|
20
|
+
solutions_or_solution = solutions_plural ? 'solutions' : 'solution'
|
18
21
|
append_to.append(child:
|
19
22
|
<<~HTML
|
20
|
-
<div class="os-eob os-
|
23
|
+
<div class="os-eob os-#{solutions_or_solution}-container" data-type="composite-page" \
|
24
|
+
data-uuid-key=".#{solutions_or_solution}#{chapter.count_in(:book)}">
|
21
25
|
<h2 data-type="document-title">
|
22
26
|
<span class="os-text">#{I18n.t(:chapter)} #{chapter.count_in(:book)}</span>
|
23
27
|
</h2>
|
@@ -28,7 +32,7 @@ module Kitchen::Directions::MoveSolutionsToAnswerKey
|
|
28
32
|
</div>
|
29
33
|
HTML
|
30
34
|
)
|
31
|
-
strategy.
|
35
|
+
strategy.bake(chapter: chapter, append_to: append_to.last_element)
|
32
36
|
end
|
33
37
|
end
|
34
38
|
end
|
data/lib/kitchen/document.rb
CHANGED
@@ -13,6 +13,8 @@ module Kitchen
|
|
13
13
|
attr_accessor :location
|
14
14
|
# @return [Config] the configuration used in this document
|
15
15
|
attr_reader :config
|
16
|
+
# @return [IdTracker] the counter for duplicate IDs
|
17
|
+
attr_reader :id_tracker
|
16
18
|
|
17
19
|
# @!method selectors
|
18
20
|
# The document's selectors
|
@@ -34,7 +36,10 @@ module Kitchen
|
|
34
36
|
# @!method to_html
|
35
37
|
# @see https://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Node#to_html-instance_method Nokogiri::XML::Node#to_html
|
36
38
|
# @return [String] the document as an HTML string
|
37
|
-
|
39
|
+
# @!method encoding
|
40
|
+
# @see https://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Document#encoding-instance_method Nokogiri::XML::Document#encoding
|
41
|
+
# @return [String] the document as an HTML string
|
42
|
+
def_delegators :@nokogiri_document, :to_xhtml, :to_s, :to_xml, :to_html, :encoding
|
38
43
|
|
39
44
|
# Return a new instance of Document
|
40
45
|
#
|
@@ -44,8 +49,7 @@ module Kitchen
|
|
44
49
|
@nokogiri_document = nokogiri_document
|
45
50
|
@location = nil
|
46
51
|
@config = config || Config.new
|
47
|
-
@
|
48
|
-
@id_copy_suffix = '_copy_'
|
52
|
+
@id_tracker = IdTracker.new
|
49
53
|
|
50
54
|
# Nokogiri by default only recognizes the namespaces on the root node. Add all others.
|
51
55
|
raw&.add_all_namespaces! if @config.enable_all_namespaces
|
@@ -148,38 +152,6 @@ module Kitchen
|
|
148
152
|
end
|
149
153
|
end
|
150
154
|
|
151
|
-
# Keeps track that an element with the given ID has been copied. When such
|
152
|
-
# elements are pasted, this information is used to give those elements unique
|
153
|
-
# IDs that don't duplicate the original element.
|
154
|
-
#
|
155
|
-
# @param id [String] the ID
|
156
|
-
#
|
157
|
-
def record_id_copied(id)
|
158
|
-
return if id.blank?
|
159
|
-
|
160
|
-
@next_paste_count_for_id[id] ||= 1
|
161
|
-
end
|
162
|
-
|
163
|
-
# Returns a unique ID given the ID of an element that was copied and is about
|
164
|
-
# to be pasted
|
165
|
-
#
|
166
|
-
# @param original_id [String]
|
167
|
-
#
|
168
|
-
def modified_id_to_paste(original_id)
|
169
|
-
return nil if original_id.nil?
|
170
|
-
return '' if original_id.blank?
|
171
|
-
|
172
|
-
count = next_count_for_pasted_id(original_id)
|
173
|
-
|
174
|
-
# A count of 0 means the element was cut and this is the first paste, do not
|
175
|
-
# modify the ID; otherwise, use the uniquified ID.
|
176
|
-
if count.zero?
|
177
|
-
original_id
|
178
|
-
else
|
179
|
-
"#{original_id}#{@id_copy_suffix}#{count}"
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
155
|
# Returns the underlying Nokogiri Document object
|
184
156
|
#
|
185
157
|
# @return [Nokogiri::XML::Document]
|
@@ -188,16 +160,19 @@ module Kitchen
|
|
188
160
|
@nokogiri_document
|
189
161
|
end
|
190
162
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
163
|
+
# Returns the locale for this document, default to `:en` if no locale detected
|
164
|
+
#
|
165
|
+
# @return [Symbol]
|
166
|
+
#
|
167
|
+
def locale
|
168
|
+
raw.root['lang']&.to_sym || begin
|
169
|
+
warn 'No `lang` attribute on this document so cannot detect its locale; defaulting to `:en`'
|
170
|
+
:en
|
198
171
|
end
|
199
172
|
end
|
200
173
|
|
174
|
+
protected
|
175
|
+
|
201
176
|
attr_reader :nokogiri_document
|
202
177
|
|
203
178
|
end
|
data/lib/kitchen/element_base.rb
CHANGED
@@ -101,6 +101,8 @@ module Kitchen
|
|
101
101
|
# @return [Clipboard]
|
102
102
|
def_delegators :document, :pantry, :clipboard
|
103
103
|
|
104
|
+
def_delegators :document, :id_tracker
|
105
|
+
|
104
106
|
# Creates a new instance
|
105
107
|
#
|
106
108
|
# @param node [Nokogiri::XML::Node] the wrapped element
|
@@ -441,6 +443,11 @@ module Kitchen
|
|
441
443
|
def cut(to: nil)
|
442
444
|
block_error_if(block_given?)
|
443
445
|
|
446
|
+
raw.traverse do |node|
|
447
|
+
next if node.text? || node.document?
|
448
|
+
|
449
|
+
id_tracker.record_id_cut(node[:id])
|
450
|
+
end
|
444
451
|
node.remove
|
445
452
|
get_clipboard(to).add(self) if to.present?
|
446
453
|
self
|
@@ -461,7 +468,7 @@ module Kitchen
|
|
461
468
|
the_copy.raw.traverse do |node|
|
462
469
|
next if node.text? || node.document?
|
463
470
|
|
464
|
-
|
471
|
+
id_tracker.record_id_copied(node[:id])
|
465
472
|
end
|
466
473
|
get_clipboard(to).add(the_copy) if to.present?
|
467
474
|
the_copy
|
@@ -472,20 +479,22 @@ module Kitchen
|
|
472
479
|
def paste
|
473
480
|
# See `clone` method for a note about namespaces
|
474
481
|
block_error_if(block_given?)
|
475
|
-
|
476
482
|
temp_copy = clone
|
477
483
|
temp_copy.raw.traverse do |node|
|
478
484
|
next if node.text? || node.document?
|
479
485
|
|
480
|
-
|
486
|
+
if node[:id].present?
|
487
|
+
id_tracker.record_id_pasted(node[:id])
|
488
|
+
node[:id] = id_tracker.modified_id_to_paste(node[:id])
|
489
|
+
end
|
481
490
|
end
|
482
491
|
temp_copy.to_s
|
483
492
|
end
|
484
493
|
|
485
494
|
# Copy the element's id
|
486
495
|
def copied_id
|
487
|
-
|
488
|
-
|
496
|
+
id_tracker.record_id_copied(id)
|
497
|
+
id_tracker.modified_id_to_paste(id)
|
489
498
|
end
|
490
499
|
|
491
500
|
# Delete the element
|
@@ -499,6 +508,21 @@ module Kitchen
|
|
499
508
|
Element.new(node: raw.parent, document: document, short_type: "parent(#{short_type})")
|
500
509
|
end
|
501
510
|
|
511
|
+
# returns previous element
|
512
|
+
# skips double indentations that the nokigiri sometimes picks up
|
513
|
+
# nil if there's no previous sibling
|
514
|
+
#
|
515
|
+
def previous
|
516
|
+
prev = raw.previous
|
517
|
+
return prev if prev.nil?
|
518
|
+
|
519
|
+
Element.new(
|
520
|
+
node: prev,
|
521
|
+
document: document,
|
522
|
+
short_type: "previous(#{short_type})"
|
523
|
+
)
|
524
|
+
end
|
525
|
+
|
502
526
|
# TODO: make it clear if all of these methods take Element, Node, or String
|
503
527
|
|
504
528
|
# If child argument given, prepends it before the element's current children.
|
@@ -578,9 +602,9 @@ module Kitchen
|
|
578
602
|
attributes.each do |k, v|
|
579
603
|
new_node[k.to_s.gsub(/([^_])_([^_])/, '\1-\2').gsub('__', '_')] = v
|
580
604
|
end
|
581
|
-
new_node.children = children
|
605
|
+
new_node.children = children
|
582
606
|
yield Element.new(node: new_node, document: document, short_type: nil) if block_given?
|
583
|
-
end
|
607
|
+
end
|
584
608
|
|
585
609
|
self
|
586
610
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
# Compare one string with another
|
5
|
+
#
|
6
|
+
# Returns 0 if first string equals second,
|
7
|
+
# 1 if first string is greater than the second
|
8
|
+
# and -1 if first string is less than the second.
|
9
|
+
#
|
10
|
+
class I18nString < String
|
11
|
+
|
12
|
+
def <=>(other)
|
13
|
+
I18n.sort_strings(self, other)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
# A class to track and modify duplicate IDs in a document
|
5
|
+
#
|
6
|
+
class IdTracker
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@id_data = Hash.new { |hash, key| hash[key] = { count: 0, last_pasted: false } }
|
10
|
+
@id_copy_suffix = '_copy_'
|
11
|
+
end
|
12
|
+
|
13
|
+
# Keeps track that an element with the given ID has been copied. When such
|
14
|
+
# elements are pasted, this information is used to give those elements unique
|
15
|
+
# IDs that don't duplicate the original element.
|
16
|
+
#
|
17
|
+
# @param id [String] the ID
|
18
|
+
#
|
19
|
+
def record_id_copied(id)
|
20
|
+
return if id.blank?
|
21
|
+
|
22
|
+
@id_data[id][:count] += 1
|
23
|
+
@id_data[id][:last_pasted] = false
|
24
|
+
end
|
25
|
+
|
26
|
+
# Keeps track that an element with the given ID has been cut.
|
27
|
+
#
|
28
|
+
# @param id [String]
|
29
|
+
#
|
30
|
+
def record_id_cut(id)
|
31
|
+
return if id.blank?
|
32
|
+
|
33
|
+
@id_data[id][:count] -= 1 if @id_data[id][:count].positive?
|
34
|
+
@id_data[id][:last_pasted] = false
|
35
|
+
end
|
36
|
+
|
37
|
+
# Keeps track that an element with the given ID has been pasted.
|
38
|
+
#
|
39
|
+
# @param id [String]
|
40
|
+
#
|
41
|
+
def record_id_pasted(id)
|
42
|
+
return if id.blank?
|
43
|
+
|
44
|
+
@id_data[id][:count] += 1 if @id_data[id][:last_pasted]
|
45
|
+
@id_data[id][:last_pasted] = true
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns a unique ID given the ID of an element that was copied and is about
|
49
|
+
# to be pasted
|
50
|
+
#
|
51
|
+
# @param original_id [String]
|
52
|
+
# @return [String]
|
53
|
+
#
|
54
|
+
def modified_id_to_paste(original_id)
|
55
|
+
return nil if original_id.nil?
|
56
|
+
return '' if original_id.blank?
|
57
|
+
|
58
|
+
count = @id_data[original_id][:count]
|
59
|
+
# A count of 0 means the element was cut and this is the first paste, do not
|
60
|
+
# modify the ID; otherwise, use the uniquified ID.
|
61
|
+
if count.zero?
|
62
|
+
original_id
|
63
|
+
else
|
64
|
+
"#{original_id}#{@id_copy_suffix}#{count}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/kitchen/oven.rb
CHANGED
@@ -28,6 +28,8 @@ module Kitchen
|
|
28
28
|
config: config
|
29
29
|
)
|
30
30
|
|
31
|
+
I18n.locale = doc.locale
|
32
|
+
|
31
33
|
[recipes].flatten.each do |recipe|
|
32
34
|
recipe.document = doc
|
33
35
|
recipe.bake
|
@@ -35,7 +37,7 @@ module Kitchen
|
|
35
37
|
profile.baked!
|
36
38
|
|
37
39
|
File.open(output_file, 'w') do |f|
|
38
|
-
f.write doc.to_xhtml(indent: 2)
|
40
|
+
f.write doc.to_xhtml(indent: 2, encoding: doc.encoding || 'utf-8')
|
39
41
|
end
|
40
42
|
profile.written!
|
41
43
|
|
data/lib/kitchen/page_element.rb
CHANGED
@@ -88,11 +88,10 @@ module Kitchen
|
|
88
88
|
|
89
89
|
# Returns the summary element.
|
90
90
|
#
|
91
|
-
# @
|
92
|
-
# @return [Element]
|
91
|
+
# @return [Element, nil] the summary or nil if no summary found
|
93
92
|
#
|
94
93
|
def summary
|
95
|
-
first
|
94
|
+
first(selectors.page_summary)
|
96
95
|
end
|
97
96
|
|
98
97
|
# Returns the exercises element.
|