openstax_kitchen 4.1.1 → 5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b80bf07271b311949246bf6a63a9d10fe5f14396175f66a129debcc9e9ef15e3
4
- data.tar.gz: 7a3a7050d134a0b106d3a80dc18add9209742fca1eea4873f351eb0dd4d05034
3
+ metadata.gz: c8e1365bab888949c899b5cb36518be9456bd23d0369ddab9a42ac81f82cc024
4
+ data.tar.gz: cd86a88028f0946885add3866ffad6133f84ce48a779800cb5105cc8153736d4
5
5
  SHA512:
6
- metadata.gz: 7fee3b2b4dd92639af2e20520c3f65a31255d944df649e91c5c0e5c8f0a8e1e1f6d19b4477480c5cbc899f7124727c8a40b5a0759985ec94225885baf36b3287
7
- data.tar.gz: ed62932aa44e597135158cc182daefd2773b89070e1d82750669d4d1f760fa8179f1197c67eddcdec73c1cdc2b1bd7537ca28c8f5603d3a2a7962457d777141f
6
+ metadata.gz: 16b9afc1d63a6098aad2396e114975ea35d39890c9a4c27c88dfef7710d129ddf16e3f18d775042ae919d0dff5284d41b53f668621d5cd74f2e723a670fd33d9
7
+ data.tar.gz: 9b93c51846a460a3e71c6a6080f53be61f1fa93ab268f954ddf3b7d447a1f9602dd789d876bc41e2997f8f44e682453c413f2f28ea7754c4d7f1015d3ecde1a6
data/CHANGELOG.md CHANGED
@@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [5.0.0] - 2021-06-02
10
+
11
+ * Reditributed duplicated id logic across `#record_id_copied`, `#record_id_cut`, `#record_id_pasted`, added a couple more tests for `#copy`, `#cut`, and `#paste`, created a new class `IdTracker` and moved `#record_id_copied`, `#record_id_cut`, `#record_id_pasted`, and `modified_id_to_paste` into the new class (major)
12
+ * Moved selectors from recipe to kitchen on `BakeFirstElements` Direction (minor)
13
+ * Auto-detect language based on document; force output encoding to UTF-8 (major)
14
+ * Switched to using a library to sort strings in a language-specific way (patch)
15
+ * Remove summary attribute from `BakeNumberedTable` (major)
16
+
9
17
  ## [4.1.1] - 2021-05-24
10
18
 
11
19
  * Adds low level Nokogiri caching, disabled by default (patch)
data/Gemfile.lock CHANGED
@@ -1,11 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openstax_kitchen (4.1.1)
4
+ openstax_kitchen (5.0.0)
5
5
  activesupport
6
6
  i18n
7
7
  nokogiri
8
8
  rainbow
9
+ twitter_cldr
9
10
 
10
11
  GEM
11
12
  remote: https://rubygems.org/
@@ -18,6 +19,8 @@ GEM
18
19
  zeitwerk (~> 2.3)
19
20
  ast (2.4.1)
20
21
  byebug (11.1.2)
22
+ camertron-eprun (1.1.1)
23
+ cldr-plurals-runtime-rb (1.1.0)
21
24
  codecov (0.2.13)
22
25
  simplecov (~> 0.18.0)
23
26
  coderay (1.1.3)
@@ -94,6 +97,10 @@ GEM
94
97
  tins (~> 1.0)
95
98
  tins (1.26.0)
96
99
  sync
100
+ twitter_cldr (6.6.0)
101
+ camertron-eprun
102
+ cldr-plurals-runtime-rb (~> 1.1)
103
+ tzinfo
97
104
  tzinfo (2.0.4)
98
105
  concurrent-ruby (~> 1.0)
99
106
  unicode-display_width (1.7.0)
@@ -3,7 +3,13 @@
3
3
  module Kitchen
4
4
  module Directions
5
5
  module BakeFirstElements
6
- def self.v1(within:, selectors:)
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')
@@ -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
- sortable <=> other.sortable
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
@@ -22,21 +22,16 @@ module Kitchen::Directions::BakeNumberedTable
22
22
  table.parent.add_class('os-column-header-container') if table.column_header?
23
23
 
24
24
  # TODO: extra spaces added here to match legacy implementation, but probably not meaningful?
25
- new_summary = "#{table_label} "
26
25
  new_caption = ''
27
26
  caption_title = ''
28
27
 
29
28
  if (title = table.first("span[data-type='title']")&.cut)
30
- new_summary += title.text
31
29
  caption_title = <<~HTML
32
30
  \n<span class="os-title" data-type="title">#{title.children}</span>
33
31
  HTML
34
32
  end
35
33
 
36
- new_summary += ' '
37
-
38
34
  if (caption = table.caption&.cut)
39
- new_summary += caption.text
40
35
  new_caption = <<~HTML
41
36
  \n<span class="os-caption">#{caption.children}</span>
42
37
  HTML
@@ -46,8 +41,6 @@ module Kitchen::Directions::BakeNumberedTable
46
41
  HTML
47
42
  end
48
43
 
49
- table[:summary] = new_summary
50
-
51
44
  return if table.unnumbered?
52
45
 
53
46
  table.append(sibling:
@@ -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
- def_delegators :@nokogiri_document, :to_xhtml, :to_s, :to_xml, :to_html
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
- @next_paste_count_for_id = {}
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
- protected
192
-
193
- def next_count_for_pasted_id(id)
194
- return if id.blank?
195
-
196
- (@next_paste_count_for_id[id] ||= 0).tap do
197
- @next_paste_count_for_id[id] += 1
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
@@ -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
- document.record_id_copied(node[:id])
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
- node[:id] = document.modified_id_to_paste(node[:id]) unless node[:id].blank?
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
- document.record_id_copied(id)
488
- document.modified_id_to_paste(id)
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
@@ -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
 
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'twitter_cldr'
4
+
5
+ # rubocop:disable Style/Documentation
6
+ module I18n
7
+ def self.sort_strings(first, second)
8
+ string_sorter.compare(first, second)
9
+ end
10
+
11
+ def self.string_sorter
12
+ @string_sorter ||= begin
13
+ # TwitterCldr does not know about our :test locale, so substitute the English one
14
+ locale = I18n.locale == :test ? :en : I18n.locale
15
+ TwitterCldr::Collation::Collator.new(locale)
16
+ end
17
+ end
18
+
19
+ def self.clear_string_sorter
20
+ @string_sorter = nil
21
+ end
22
+
23
+ class <<self
24
+ alias_method :original_locale=, :locale=
25
+ end
26
+
27
+ def self.locale=(locale)
28
+ # We wrap the setting of locale so that we can clear the string sorter (so that it
29
+ # gets reset to the new locale the next time it is used)
30
+ clear_string_sorter
31
+ self.original_locale = locale
32
+ end
33
+ end
34
+ # rubocop:enable Style/Documentation
@@ -3,5 +3,5 @@
3
3
  # A library for modifying the structure of OpenStax book XML.
4
4
  #
5
5
  module Kitchen
6
- VERSION = '4.1.1'
6
+ VERSION = '5.0.0'
7
7
  end
@@ -0,0 +1,32 @@
1
+ es:
2
+ figure: Figura
3
+ table_label: Tabla
4
+ appendix: Apéndice
5
+ theorem: Teorema
6
+ solution: Solución
7
+ chapter_outline: Esquema Del Capitulo
8
+ toc_title: Contenido
9
+ example_label: Ejemplo
10
+ exercise_label: Ejercicio
11
+ equation: Ecuación
12
+ chapter: Capítulo
13
+ unit: Unidad
14
+ checkpoint: Punto De Control
15
+ chapter_review: Revisión Del Capítulo
16
+ learning_objectives: Objetivos De Aprendizaje
17
+ stepwise_step_label: Paso
18
+ references: Referencias
19
+ eoc_chapter_review: Revisión Del Capítulo
20
+ eoc_key_terms_title: Términos Clave
21
+ eoc_summary_title: Resumen
22
+ eoc_exercises_title: Ejercicios
23
+ eoc_composite_metadata_title: Revisión Del Capítulo
24
+ eoc_answer_key_title: Respuestas Clave
25
+ eoc_key_concepts: Conceptos Clave
26
+ eoc_key_equations: Ecuaciones Clave
27
+ eoc_suggested_reading: Sugerencias Para Estudios Adicionales
28
+ eoc_further_research_title: Investigación Adicional
29
+ eob_index_title: Índice
30
+ eob_index_symbols_group: Símbolos
31
+ review_exercises: Ejercicios De Repaso
32
+ section_exercises: ! 'Sección %{number} Ejercicios'
@@ -25,7 +25,6 @@ require 'kitchen/selectors/base'
25
25
  require_all('kitchen/selectors')
26
26
 
27
27
  require 'kitchen/utils'
28
- require 'kitchen/transliterations'
29
28
  require 'kitchen/errors'
30
29
  require 'kitchen/ancestor'
31
30
  require 'kitchen/search_query'
@@ -41,6 +40,7 @@ require 'kitchen/clipboard'
41
40
  require 'kitchen/pantry'
42
41
  require 'kitchen/counter'
43
42
  require 'kitchen/selector'
43
+ require 'kitchen/id_tracker'
44
44
 
45
45
  require 'kitchen/element_enumerator_base'
46
46
  require 'kitchen/element_enumerator_factory'
@@ -53,7 +53,3 @@ require 'kitchen/element_factory'
53
53
  require_all('kitchen/directions')
54
54
 
55
55
  I18n.backend.load_translations(file_glob('/locales/*.yml'))
56
-
57
- I18n.available_locales.each do |available_locale|
58
- I18n.backend.store_translations(available_locale, Kitchen::TRANSLITERATIONS)
59
- end
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.add_dependency 'i18n'
34
34
  spec.add_dependency 'nokogiri'
35
35
  spec.add_dependency 'rainbow'
36
+ spec.add_dependency 'twitter_cldr'
36
37
 
37
38
  spec.add_development_dependency 'byebug'
38
39
  spec.add_development_dependency 'inch'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstax_kitchen
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Slavinsky
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-24 00:00:00.000000000 Z
11
+ date: 2021-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: twitter_cldr
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: byebug
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -311,6 +325,7 @@ files:
311
325
  - lib/kitchen/exercise_element_enumerator.rb
312
326
  - lib/kitchen/figure_element.rb
313
327
  - lib/kitchen/figure_element_enumerator.rb
328
+ - lib/kitchen/id_tracker.rb
314
329
  - lib/kitchen/metadata_element.rb
315
330
  - lib/kitchen/metadata_element_enumerator.rb
316
331
  - lib/kitchen/mixins/block_error_if.rb
@@ -320,6 +335,7 @@ files:
320
335
  - lib/kitchen/page_element.rb
321
336
  - lib/kitchen/page_element_enumerator.rb
322
337
  - lib/kitchen/pantry.rb
338
+ - lib/kitchen/patches/i18n.rb
323
339
  - lib/kitchen/patches/nokogiri.rb
324
340
  - lib/kitchen/patches/nokogiri_profiling.rb
325
341
  - lib/kitchen/patches/renderable.rb
@@ -338,13 +354,13 @@ files:
338
354
  - lib/kitchen/templates/eoc_section_title_template.xhtml.erb
339
355
  - lib/kitchen/term_element.rb
340
356
  - lib/kitchen/term_element_enumerator.rb
341
- - lib/kitchen/transliterations.rb
342
357
  - lib/kitchen/type_casting_element_enumerator.rb
343
358
  - lib/kitchen/unit_element.rb
344
359
  - lib/kitchen/unit_element_enumerator.rb
345
360
  - lib/kitchen/utils.rb
346
361
  - lib/kitchen/version.rb
347
362
  - lib/locales/en.yml
363
+ - lib/locales/es.yml
348
364
  - lib/locales/pl.yml
349
365
  - lib/notes.md
350
366
  - lib/openstax_kitchen.rb
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kitchen
4
- # These are added to every translation locale, including the `test` locale
5
- # set by `stub_locales`. When we sort strings with accent marks, we use
6
- # `ActiveSupport::Inflector.transliterate` to ensure that the sorting is
7
- # sensible. This method does not know about Greek characters by default so
8
- # we teach it about them by adding the rules below to the i18n configuration.
9
- #
10
- TRANSLITERATIONS = {
11
- i18n: {
12
- transliterate: {
13
- rule: {
14
- σ: 'σ',
15
- Δ: 'Δ',
16
- π: 'π'
17
- }
18
- }
19
- }
20
- }.freeze
21
- end