openstax_kitchen 4.1.1 → 5.0.0

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