openstax_kitchen 4.1.0 → 4.1.1
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/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/README.md +16 -0
- data/codecov.yaml +1 -0
- data/lib/kitchen/book_document.rb +1 -1
- data/lib/kitchen/chapter_element.rb +2 -2
- data/lib/kitchen/composite_chapter_element_enumerator.rb +21 -0
- data/lib/kitchen/config.rb +7 -0
- data/lib/kitchen/directions/bake_chapter_key_concepts/v1.rb +1 -1
- data/lib/kitchen/directions/bake_composite_chapters.rb +1 -1
- data/lib/kitchen/directions/bake_composite_pages.rb +1 -1
- data/lib/kitchen/directions/bake_equations.rb +1 -1
- data/lib/kitchen/directions/book_answer_key_container/v1.rb +1 -1
- data/lib/kitchen/directions/chapter_review_container/v1.rb +1 -1
- data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/uphysics.rb +2 -2
- data/lib/kitchen/document.rb +2 -10
- data/lib/kitchen/element_base.rb +19 -7
- data/lib/kitchen/element_enumerator_base.rb +24 -1
- data/lib/kitchen/element_enumerator_factory.rb +19 -7
- data/lib/kitchen/exercise_element.rb +2 -2
- data/lib/kitchen/oven.rb +2 -0
- data/lib/kitchen/page_element.rb +5 -2
- data/lib/kitchen/patches/nokogiri.rb +15 -0
- data/lib/kitchen/patches/nokogiri_profiling.rb +60 -0
- data/lib/kitchen/search_query.rb +6 -0
- data/lib/kitchen/selector.rb +2 -1
- data/lib/kitchen/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b80bf07271b311949246bf6a63a9d10fe5f14396175f66a129debcc9e9ef15e3
|
4
|
+
data.tar.gz: 7a3a7050d134a0b106d3a80dc18add9209742fca1eea4873f351eb0dd4d05034
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fee3b2b4dd92639af2e20520c3f65a31255d944df649e91c5c0e5c8f0a8e1e1f6d19b4477480c5cbc899f7124727c8a40b5a0759985ec94225885baf36b3287
|
7
|
+
data.tar.gz: ed62932aa44e597135158cc182daefd2773b89070e1d82750669d4d1f760fa8179f1197c67eddcdec73c1cdc2b1bd7537ca28c8f5603d3a2a7962457d777141f
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [4.1.1] - 2021-05-24
|
10
|
+
|
11
|
+
* Adds low level Nokogiri caching, disabled by default (patch)
|
12
|
+
* Cache Selector objects since they don't change (patch)
|
13
|
+
* Use more specific selectors when to reduce bake time (patch)
|
14
|
+
|
9
15
|
## [4.1.0] - 2021-05-18
|
10
16
|
|
11
17
|
* Fixed performance problem with element class detection (patch)
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -641,6 +641,22 @@ expect(book_1).to match_normalized_html("some string of HTML here")
|
|
641
641
|
expect(book_1).to match_html_nodes("some string of HTML here")
|
642
642
|
```
|
643
643
|
|
644
|
+
### Profiling
|
645
|
+
|
646
|
+
If you set the `PROFILE` environment variable to something before you run specs or a recipe, search query profile data will be collected and printed, e.g.
|
647
|
+
|
648
|
+
```bash
|
649
|
+
%> PROFILE=1 rspec
|
650
|
+
```
|
651
|
+
|
652
|
+
### Caching
|
653
|
+
|
654
|
+
There's a low-level CSS query caching tool that saves repeated queries. In some tests, it saves 15% of query time. It is disabled by default (because we aren't super sure that it is completely safe) but can be turned on with
|
655
|
+
|
656
|
+
```ruby
|
657
|
+
doc.config.enable_search_cache = true
|
658
|
+
```
|
659
|
+
|
644
660
|
### VSCode
|
645
661
|
|
646
662
|
1. Visit `vscode:extension/ms-vscode-remote.remote-containers` in a browser
|
data/codecov.yaml
CHANGED
@@ -41,7 +41,7 @@ module Kitchen
|
|
41
41
|
# @return [Element, nil]
|
42
42
|
#
|
43
43
|
def introduction_page
|
44
|
-
pages('
|
44
|
+
pages('$.introduction').first
|
45
45
|
end
|
46
46
|
|
47
47
|
# Returns an enumerator for the glossaries
|
@@ -65,7 +65,7 @@ module Kitchen
|
|
65
65
|
# @return [ElementEnumerator]
|
66
66
|
#
|
67
67
|
def abstracts
|
68
|
-
search('[data-type="abstract"]')
|
68
|
+
search('div[data-type="abstract"]')
|
69
69
|
end
|
70
70
|
|
71
71
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
# An enumerator for composite page elements
|
5
|
+
#
|
6
|
+
class CompositeChapterElementEnumerator < ElementEnumeratorBase
|
7
|
+
|
8
|
+
# Returns a factory for this enumerator
|
9
|
+
#
|
10
|
+
# @return [ElementEnumeratorFactory]
|
11
|
+
#
|
12
|
+
def self.factory
|
13
|
+
ElementEnumeratorFactory.new(
|
14
|
+
default_css_or_xpath: Selector.named(:composite_chapter),
|
15
|
+
sub_element_class: CompositeChapterElement,
|
16
|
+
enumerator_class: self
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/kitchen/config.rb
CHANGED
@@ -17,6 +17,12 @@ module Kitchen
|
|
17
17
|
#
|
18
18
|
attr_accessor :enable_all_namespaces
|
19
19
|
|
20
|
+
# @!attribute [rw] enable_search_cache
|
21
|
+
#
|
22
|
+
# @return [Boolean]
|
23
|
+
#
|
24
|
+
attr_accessor :enable_search_cache
|
25
|
+
|
20
26
|
# Creates a new config from a file (not implemented)
|
21
27
|
#
|
22
28
|
def self.new_from_file(_file)
|
@@ -28,6 +34,7 @@ module Kitchen
|
|
28
34
|
def initialize(hash: {}, selectors: nil)
|
29
35
|
@selectors = selectors || Kitchen::Selectors::Standard1.new
|
30
36
|
@enable_all_namespaces = hash[:enable_all_namespaces] || true
|
37
|
+
@enable_search_cache = hash[:enable_search_cache] || false
|
31
38
|
@hash = hash
|
32
39
|
end
|
33
40
|
end
|
@@ -19,7 +19,7 @@ module Kitchen::Directions::BakeChapterKeyConcepts
|
|
19
19
|
key_concepts.each do |key_concept|
|
20
20
|
key_concept.prepend(child: title)
|
21
21
|
key_concept.wrap("<div class='os-section-area'>")
|
22
|
-
page.search('.os-section-area').first.cut(to: key_concepts_clipboard)
|
22
|
+
page.search('div.os-section-area').first.cut(to: key_concepts_clipboard)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -4,7 +4,7 @@ module Kitchen
|
|
4
4
|
module Directions
|
5
5
|
module BakeCompositeChapters
|
6
6
|
def self.v1(book:)
|
7
|
-
book.
|
7
|
+
book.composite_chapters.each do |chapter|
|
8
8
|
chapter.first("[data-type='document-title']").id =
|
9
9
|
"composite-chapter-#{chapter.count_in(:book)}"
|
10
10
|
end
|
@@ -4,7 +4,7 @@ module Kitchen
|
|
4
4
|
module Directions
|
5
5
|
module BakeEquations
|
6
6
|
def self.v1(book:, number_decorator: :none)
|
7
|
-
book.chapters.search('[data-type="equation"]:not(.unnumbered)').each do |eq|
|
7
|
+
book.chapters.search('div[data-type="equation"]:not(.unnumbered)').each do |eq|
|
8
8
|
chapter = eq.ancestor(:chapter)
|
9
9
|
number = "#{chapter.count_in(:book)}.#{eq.count_in(:chapter)}"
|
10
10
|
|
@@ -7,7 +7,7 @@ module Kitchen::Directions::BookAnswerKeyContainer
|
|
7
7
|
def bake(book:)
|
8
8
|
@metadata = book.metadata.children_to_keep.copy
|
9
9
|
book.body.append(child: render(file: 'eob_solutions_container.xhtml.erb'))
|
10
|
-
book.body.first('.os-eob.os-solutions-container')
|
10
|
+
book.body.first('div.os-eob.os-solutions-container')
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -7,7 +7,7 @@ module Kitchen::Directions::ChapterReviewContainer
|
|
7
7
|
def bake(chapter:, metadata_source:)
|
8
8
|
@metadata = metadata_source.children_to_keep.copy
|
9
9
|
chapter.append(child: render(file: 'chapter_review.xhtml.erb'))
|
10
|
-
chapter.first('.os-eoc.os-chapter-review-container')
|
10
|
+
chapter.first('div.os-eoc.os-chapter-review-container')
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -18,7 +18,7 @@ module Kitchen::Directions::MoveSolutionsToAnswerKey
|
|
18
18
|
def bake_section(chapter:, append_to:, klass:)
|
19
19
|
section_solutions_set = []
|
20
20
|
chapter.search(".#{klass}").each do |section|
|
21
|
-
section.search('[data-type="solution"]').each do |solution|
|
21
|
+
section.search('div[data-type="solution"]').each do |solution|
|
22
22
|
section_solutions_set.push(solution.cut)
|
23
23
|
end
|
24
24
|
end
|
@@ -31,7 +31,7 @@ module Kitchen::Directions::MoveSolutionsToAnswerKey
|
|
31
31
|
|
32
32
|
def bake_from_notes(chapter:, append_to:, klass:)
|
33
33
|
solutions = []
|
34
|
-
chapter.notes("
|
34
|
+
chapter.notes("$.#{klass}").each do |note|
|
35
35
|
note.exercises.each do |exercise|
|
36
36
|
solution = exercise.solution
|
37
37
|
solutions.push(solution.cut) if solution
|
data/lib/kitchen/document.rb
CHANGED
@@ -47,16 +47,8 @@ module Kitchen
|
|
47
47
|
@next_paste_count_for_id = {}
|
48
48
|
@id_copy_suffix = '_copy_'
|
49
49
|
|
50
|
-
# Nokogiri by default only recognizes the namespaces on the root node.
|
51
|
-
|
52
|
-
return unless @config.enable_all_namespaces && raw.present?
|
53
|
-
|
54
|
-
raw.collect_namespaces.each do |namespace, url|
|
55
|
-
prefix, name = namespace.split(':')
|
56
|
-
next unless prefix == 'xmlns' && name.present?
|
57
|
-
|
58
|
-
raw.root.add_namespace_definition(name, url)
|
59
|
-
end
|
50
|
+
# Nokogiri by default only recognizes the namespaces on the root node. Add all others.
|
51
|
+
raw&.add_all_namespaces! if @config.enable_all_namespaces
|
60
52
|
end
|
61
53
|
|
62
54
|
# Returns an enumerator that iterates over all children of this document
|
data/lib/kitchen/element_base.rb
CHANGED
@@ -132,6 +132,7 @@ module Kitchen
|
|
132
132
|
@ancestors = HashWithIndifferentAccess.new
|
133
133
|
@search_query_matches_that_have_been_counted = {}
|
134
134
|
@is_a_clone = false
|
135
|
+
@search_cache = {}
|
135
136
|
end
|
136
137
|
|
137
138
|
# Returns ElementBase descendent type or nil if none found
|
@@ -345,7 +346,7 @@ module Kitchen
|
|
345
346
|
# search results if the method or callable returns false
|
346
347
|
# @return [ElementEnumerator]
|
347
348
|
#
|
348
|
-
def search(*selector_or_xpath_args, only: nil, except: nil)
|
349
|
+
def search(*selector_or_xpath_args, only: nil, except: nil, reload: false)
|
349
350
|
block_error_if(block_given?)
|
350
351
|
|
351
352
|
ElementEnumerator.factory.build_within(
|
@@ -354,19 +355,29 @@ module Kitchen
|
|
354
355
|
css_or_xpath: selector_or_xpath_args,
|
355
356
|
only: only,
|
356
357
|
except: except
|
357
|
-
)
|
358
|
+
),
|
359
|
+
reload: reload
|
358
360
|
)
|
359
361
|
end
|
360
362
|
|
363
|
+
def raw_search(*selector_or_xpath_args, reload: false)
|
364
|
+
key = selector_or_xpath_args
|
365
|
+
@search_cache[key] = nil if reload || !config.enable_search_cache
|
366
|
+
# cache nil search results with a fake -1 value
|
367
|
+
@search_cache[key] ||= raw.search(*selector_or_xpath_args) || -1
|
368
|
+
@search_cache[key] == -1 ? nil : @search_cache[key]
|
369
|
+
end
|
370
|
+
|
361
371
|
# Yields and returns the first child element that matches the provided
|
362
372
|
# selector or XPath arguments.
|
363
373
|
#
|
364
374
|
# @param selector_or_xpath_args [Array<String>] CSS selectors or XPath arguments
|
375
|
+
# @param reload [Boolean] ignores cache if true
|
365
376
|
# @yieldparam [Element] the matched XML element
|
366
377
|
# @return [Element, nil] the matched XML element or nil if no match found
|
367
378
|
#
|
368
|
-
def first(*selector_or_xpath_args)
|
369
|
-
search(*selector_or_xpath_args).first.tap do |element|
|
379
|
+
def first(*selector_or_xpath_args, reload: false)
|
380
|
+
search(*selector_or_xpath_args, reload: reload).first.tap do |element|
|
370
381
|
yield(element) if block_given?
|
371
382
|
end
|
372
383
|
end
|
@@ -375,12 +386,13 @@ module Kitchen
|
|
375
386
|
# selector or XPath arguments.
|
376
387
|
#
|
377
388
|
# @param selector_or_xpath_args [Array<String>] CSS selectors or XPath arguments
|
389
|
+
# @param reload [Boolean] ignores cache if true
|
378
390
|
# @yieldparam [Element] the matched XML element
|
379
391
|
# @raise [ElementNotFoundError] if no matching element is found
|
380
392
|
# @return [Element] the matched XML element
|
381
393
|
#
|
382
|
-
def first!(*selector_or_xpath_args)
|
383
|
-
search(*selector_or_xpath_args).first!.tap do |element|
|
394
|
+
def first!(*selector_or_xpath_args, reload: false)
|
395
|
+
search(*selector_or_xpath_args, reload: reload).first!.tap do |element|
|
384
396
|
yield(element) if block_given?
|
385
397
|
end
|
386
398
|
end
|
@@ -694,7 +706,7 @@ module Kitchen
|
|
694
706
|
# Returns a pages enumerator
|
695
707
|
def_delegators :as_enumerator, :pages, :chapters, :terms, :figures, :notes, :tables, :examples,
|
696
708
|
:metadatas, :non_introduction_pages, :units, :titles, :exercises, :references,
|
697
|
-
:composite_pages
|
709
|
+
:composite_pages, :composite_chapters
|
698
710
|
|
699
711
|
# Returns this element as an enumerator (over only one element, itself)
|
700
712
|
#
|
@@ -84,7 +84,30 @@ module Kitchen
|
|
84
84
|
#
|
85
85
|
def composite_pages(css_or_xpath=nil, only: nil, except: nil)
|
86
86
|
block_error_if(block_given?)
|
87
|
-
chain_to(CompositePageElementEnumerator,
|
87
|
+
chain_to(CompositePageElementEnumerator,
|
88
|
+
css_or_xpath: css_or_xpath,
|
89
|
+
only: only,
|
90
|
+
except: except)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns an enumerator that iterates through composite chapters within the scope of this enumerator
|
94
|
+
#
|
95
|
+
# @param css_or_xpath [String] additional selectors to further narrow the element iterated over;
|
96
|
+
# a "$" in this argument will be replaced with the default selector for the element being
|
97
|
+
# iterated over.
|
98
|
+
# @param only [Symbol, Callable] the name of a method to call on an element or a
|
99
|
+
# lambda or proc that accepts an element; elements will only be included in the
|
100
|
+
# search results if the method or callable returns true
|
101
|
+
# @param except [Symbol, Callable] the name of a method to call on an element or a
|
102
|
+
# lambda or proc that accepts an element; elements will not be included in the
|
103
|
+
# search results if the method or callable returns false
|
104
|
+
#
|
105
|
+
def composite_chapters(css_or_xpath=nil, only: nil, except: nil)
|
106
|
+
block_error_if(block_given?)
|
107
|
+
chain_to(CompositeChapterElementEnumerator,
|
108
|
+
css_or_xpath: css_or_xpath,
|
109
|
+
only: only,
|
110
|
+
except: except)
|
88
111
|
end
|
89
112
|
|
90
113
|
# Returns an enumerator that iterates through pages that arent the introduction page within the scope of this enumerator
|
@@ -39,12 +39,22 @@ module Kitchen
|
|
39
39
|
# @return [ElementEnumeratorBase] actually returns the concrete enumerator class
|
40
40
|
# given to the factory in its constructor.
|
41
41
|
#
|
42
|
-
def build_within(enumerator_or_element, search_query: SearchQuery.new)
|
42
|
+
def build_within(enumerator_or_element, search_query: SearchQuery.new, reload: false)
|
43
43
|
case enumerator_or_element
|
44
44
|
when ElementBase
|
45
|
-
build_within_element(enumerator_or_element,
|
45
|
+
build_within_element(enumerator_or_element,
|
46
|
+
search_query: search_query,
|
47
|
+
reload: reload)
|
46
48
|
when ElementEnumeratorBase
|
47
|
-
|
49
|
+
if enumerator_class != ElementEnumerator && !search_query.expects_substitution?
|
50
|
+
raise "Query #{search_query} is missing the substitution character ('$') but " \
|
51
|
+
"is run with an enumerator #{enumerator_class.name} that has its own " \
|
52
|
+
"selectors for substitution."
|
53
|
+
end
|
54
|
+
|
55
|
+
build_within_other_enumerator(enumerator_or_element,
|
56
|
+
search_query: search_query,
|
57
|
+
reload: reload)
|
48
58
|
end
|
49
59
|
end
|
50
60
|
|
@@ -64,7 +74,7 @@ module Kitchen
|
|
64
74
|
|
65
75
|
protected
|
66
76
|
|
67
|
-
def build_within_element(element, search_query:)
|
77
|
+
def build_within_element(element, search_query:, reload:)
|
68
78
|
search_query.apply_default_css_or_xpath_and_normalize(default_css_or_xpath,
|
69
79
|
config: element.config)
|
70
80
|
|
@@ -77,7 +87,7 @@ module Kitchen
|
|
77
87
|
# below, the counts are correct.
|
78
88
|
element.uncount(search_query)
|
79
89
|
|
80
|
-
element.
|
90
|
+
element.raw_search(*search_query.css_or_xpath, reload: reload).each do |sub_node|
|
81
91
|
sub_element = ElementFactory.build_from_node(
|
82
92
|
node: sub_node,
|
83
93
|
document: element.document,
|
@@ -105,13 +115,15 @@ module Kitchen
|
|
105
115
|
end
|
106
116
|
end
|
107
117
|
|
108
|
-
def build_within_other_enumerator(other_enumerator, search_query:)
|
118
|
+
def build_within_other_enumerator(other_enumerator, search_query:, reload:)
|
109
119
|
# Return a new enumerator instance that internally iterates over `other_enumerator`
|
110
120
|
# running a new enumerator for each element returned by that other enumerator.
|
111
121
|
enumerator_class.new(search_query: search_query,
|
112
122
|
upstream_enumerator: other_enumerator) do |block|
|
113
123
|
other_enumerator.each do |element|
|
114
|
-
build_within_element(element,
|
124
|
+
build_within_element(element,
|
125
|
+
search_query: search_query,
|
126
|
+
reload: reload).each do |sub_element|
|
115
127
|
block.yield(sub_element)
|
116
128
|
end
|
117
129
|
end
|
@@ -28,7 +28,7 @@ module Kitchen
|
|
28
28
|
# @return ElementEnumerator
|
29
29
|
#
|
30
30
|
def problem
|
31
|
-
first("[data-type='problem']")
|
31
|
+
first("div[data-type='problem']")
|
32
32
|
end
|
33
33
|
|
34
34
|
# Returns the enumerator for solution.
|
@@ -36,7 +36,7 @@ module Kitchen
|
|
36
36
|
# @return ElementEnumerator
|
37
37
|
#
|
38
38
|
def solution
|
39
|
-
first("[data-type='solution']")
|
39
|
+
first("div[data-type='solution']")
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
data/lib/kitchen/oven.rb
CHANGED
data/lib/kitchen/page_element.rb
CHANGED
@@ -29,9 +29,12 @@ module Kitchen
|
|
29
29
|
# @raise [ElementNotFoundError] if no matching element is found
|
30
30
|
# @return [Element]
|
31
31
|
#
|
32
|
-
def title
|
32
|
+
def title(reload: false)
|
33
33
|
# The selector for intro titles changes during the baking process
|
34
|
-
|
34
|
+
@title ||= begin
|
35
|
+
selector = is_introduction? ? selectors.title_in_introduction_page : selectors.title_in_page
|
36
|
+
first!(selector, reload: reload)
|
37
|
+
end
|
35
38
|
end
|
36
39
|
|
37
40
|
# Returns the title's text regardless of whether the title has been baked
|
@@ -31,6 +31,21 @@ module Nokogiri
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
|
+
|
35
|
+
def add_all_namespaces!
|
36
|
+
# Nokogiri by default only recognizes the namespaces on the root node. Collect all
|
37
|
+
# namespaces and add them manually.
|
38
|
+
return if @all_namespaces_added
|
39
|
+
|
40
|
+
collect_namespaces.each do |namespace, url|
|
41
|
+
prefix, name = namespace.split(':')
|
42
|
+
next unless prefix == 'xmlns' && name.present?
|
43
|
+
|
44
|
+
root.add_namespace_definition(name, url)
|
45
|
+
end
|
46
|
+
|
47
|
+
@all_namespaces_added = true
|
48
|
+
end
|
34
49
|
end
|
35
50
|
|
36
51
|
# Monkey patches for Nokogiri::XML::Node
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Style/Documentation
|
4
|
+
|
5
|
+
# Make debug output more useful (dumping entire document out is not useful)
|
6
|
+
module Nokogiri
|
7
|
+
module XML
|
8
|
+
# rubocop:disable Style/MutableConstant
|
9
|
+
PROFILE_DATA = {}
|
10
|
+
# rubocop:enable Style/MutableConstant
|
11
|
+
|
12
|
+
if ENV['PROFILE']
|
13
|
+
ENV['VERBOSE_PROFILE'] = 1 if ENV['PROFILE'].to_s.downcase == 'verbose'
|
14
|
+
|
15
|
+
# Patches inside Nokogiri to count, time, and print searches. At end of baking
|
16
|
+
# you can `puts Nokogiri::XML::PROFILE_DATA` to see the totals. The counts
|
17
|
+
# hash is defined outside of the if block so that code that prints it doesn't
|
18
|
+
# explode if run without the env var. The `print_profile_data` method is also
|
19
|
+
# provided for a nice printout
|
20
|
+
|
21
|
+
def self.print_profile_data
|
22
|
+
total_duration = 0
|
23
|
+
|
24
|
+
sorted_profile_data = PROFILE_DATA.sort_by { |_, data| data[:time] / data[:count] }.reverse
|
25
|
+
|
26
|
+
puts "\nSearch Profile Data"
|
27
|
+
puts '-----------------------------------------------------------------'
|
28
|
+
puts "#{'Total Time (ms)'.ljust(17)}#{'Avg Time (ms)'.ljust(15)}#{'Count'.ljust(7)}Query"
|
29
|
+
puts '-----------------------------------------------------------------'
|
30
|
+
|
31
|
+
sorted_profile_data.each do |search_path, data|
|
32
|
+
total_time = format('%0.4f', (data[:time] * 1000))
|
33
|
+
avg_time = format('%0.4f', ((data[:time] / data[:count]) * 1000))
|
34
|
+
puts total_time.ljust(17) + avg_time.to_s.ljust(15) + data[:count].to_s.ljust(7) + \
|
35
|
+
search_path
|
36
|
+
total_duration += data[:time] * 1000
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "\nTotal time across all searches (ms): #{total_duration}"
|
40
|
+
end
|
41
|
+
|
42
|
+
class XPathContext
|
43
|
+
alias_method :original_evaluate, :evaluate
|
44
|
+
def evaluate(search_path, handler=nil)
|
45
|
+
puts search_path if ENV['VERBOSE_PROFILE']
|
46
|
+
|
47
|
+
PROFILE_DATA[search_path] ||= Hash.new(0)
|
48
|
+
PROFILE_DATA[search_path][:count] += 1
|
49
|
+
|
50
|
+
start_time = Time.now
|
51
|
+
original_evaluate(search_path, handler).tap do
|
52
|
+
PROFILE_DATA[search_path][:time] += Time.now - start_time
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# rubocop:enable Style/Documentation
|
data/lib/kitchen/search_query.rb
CHANGED
@@ -82,6 +82,12 @@ module Kitchen
|
|
82
82
|
as_type
|
83
83
|
end
|
84
84
|
|
85
|
+
# Returns true if the query has the substitution character ('$')
|
86
|
+
#
|
87
|
+
def expects_substitution?
|
88
|
+
css_or_xpath.nil? || [css_or_xpath].flatten.all? { |item| item.include?('$') }
|
89
|
+
end
|
90
|
+
|
85
91
|
protected
|
86
92
|
|
87
93
|
def condition_passes?(method_or_callable, element, success_outcome)
|
data/lib/kitchen/selector.rb
CHANGED
data/lib/kitchen/version.rb
CHANGED
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.
|
4
|
+
version: 4.1.1
|
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-
|
11
|
+
date: 2021-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -220,6 +220,7 @@ files:
|
|
220
220
|
- lib/kitchen/chapter_element_enumerator.rb
|
221
221
|
- lib/kitchen/clipboard.rb
|
222
222
|
- lib/kitchen/composite_chapter_element.rb
|
223
|
+
- lib/kitchen/composite_chapter_element_enumerator.rb
|
223
224
|
- lib/kitchen/composite_page_element.rb
|
224
225
|
- lib/kitchen/composite_page_element_enumerator.rb
|
225
226
|
- lib/kitchen/config.rb
|
@@ -320,6 +321,7 @@ files:
|
|
320
321
|
- lib/kitchen/page_element_enumerator.rb
|
321
322
|
- lib/kitchen/pantry.rb
|
322
323
|
- lib/kitchen/patches/nokogiri.rb
|
324
|
+
- lib/kitchen/patches/nokogiri_profiling.rb
|
323
325
|
- lib/kitchen/patches/renderable.rb
|
324
326
|
- lib/kitchen/patches/string.rb
|
325
327
|
- lib/kitchen/recipe.rb
|