openstax_kitchen 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.devcontainer/devcontainer.json +19 -0
- data/.github/workflows/tests.yml +36 -0
- data/.gitignore +20 -0
- data/.rspec +3 -0
- data/.solargraph.yml +15 -0
- data/CHANGELOG.md +11 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Dockerfile +19 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +74 -0
- data/LICENSE.txt +21 -0
- data/README.md +674 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/normalize +79 -0
- data/bin/setup +8 -0
- data/books/chemistry2e/bake.rb +133 -0
- data/codecov.yaml +27 -0
- data/docker-compose.yml +12 -0
- data/docker/bash +1 -0
- data/docker/entrypoint +9 -0
- data/lib/kitchen.rb +57 -0
- data/lib/kitchen/ancestor.rb +30 -0
- data/lib/kitchen/book_document.rb +18 -0
- data/lib/kitchen/book_element.rb +24 -0
- data/lib/kitchen/book_element_enumerator.rb +5 -0
- data/lib/kitchen/book_recipe.rb +25 -0
- data/lib/kitchen/chapter_element.rb +35 -0
- data/lib/kitchen/chapter_element_enumerator.rb +13 -0
- data/lib/kitchen/clipboard.rb +37 -0
- data/lib/kitchen/composite_chapter_element.rb +23 -0
- data/lib/kitchen/composite_page_element.rb +27 -0
- data/lib/kitchen/composite_page_element_enumerator.rb +13 -0
- data/lib/kitchen/config.rb +20 -0
- data/lib/kitchen/counter.rb +34 -0
- data/lib/kitchen/debug/print_recipe_error.rb +80 -0
- data/lib/kitchen/directions/bake_appendix.rb +26 -0
- data/lib/kitchen/directions/bake_chapter_glossary.rb +34 -0
- data/lib/kitchen/directions/bake_chapter_introductions.rb +58 -0
- data/lib/kitchen/directions/bake_chapter_key_equations.rb +30 -0
- data/lib/kitchen/directions/bake_chapter_summary.rb +52 -0
- data/lib/kitchen/directions/bake_composite_pages.rb +13 -0
- data/lib/kitchen/directions/bake_example.rb +31 -0
- data/lib/kitchen/directions/bake_exercises.rb +164 -0
- data/lib/kitchen/directions/bake_figure.rb +25 -0
- data/lib/kitchen/directions/bake_footnotes/main.rb +11 -0
- data/lib/kitchen/directions/bake_footnotes/v1.rb +38 -0
- data/lib/kitchen/directions/bake_index/main.rb +11 -0
- data/lib/kitchen/directions/bake_index/v1.rb +138 -0
- data/lib/kitchen/directions/bake_index/v1.xhtml.erb +28 -0
- data/lib/kitchen/directions/bake_math_in_paragraph.rb +13 -0
- data/lib/kitchen/directions/bake_notes.rb +58 -0
- data/lib/kitchen/directions/bake_numbered_table/main.rb +11 -0
- data/lib/kitchen/directions/bake_numbered_table/v1.rb +47 -0
- data/lib/kitchen/directions/bake_stepwise.rb +27 -0
- data/lib/kitchen/directions/bake_toc.rb +103 -0
- data/lib/kitchen/directions/bake_unnumbered_tables.rb +14 -0
- data/lib/kitchen/directions/move_title_text_into_span.rb +15 -0
- data/lib/kitchen/document.rb +142 -0
- data/lib/kitchen/element.rb +15 -0
- data/lib/kitchen/element_base.rb +444 -0
- data/lib/kitchen/element_enumerator.rb +12 -0
- data/lib/kitchen/element_enumerator_base.rb +101 -0
- data/lib/kitchen/element_enumerator_factory.rb +111 -0
- data/lib/kitchen/element_factory.rb +32 -0
- data/lib/kitchen/errors.rb +4 -0
- data/lib/kitchen/example_element.rb +20 -0
- data/lib/kitchen/example_element_enumerator.rb +13 -0
- data/lib/kitchen/figure_element.rb +20 -0
- data/lib/kitchen/figure_element_enumerator.rb +13 -0
- data/lib/kitchen/mixins/block_error_if.rb +19 -0
- data/lib/kitchen/note_element.rb +43 -0
- data/lib/kitchen/note_element_enumerator.rb +13 -0
- data/lib/kitchen/oven.rb +61 -0
- data/lib/kitchen/page_element.rb +51 -0
- data/lib/kitchen/page_element_enumerator.rb +13 -0
- data/lib/kitchen/pantry.rb +35 -0
- data/lib/kitchen/patches/nokogiri.rb +31 -0
- data/lib/kitchen/patches/renderable.rb +31 -0
- data/lib/kitchen/patches/string.rb +5 -0
- data/lib/kitchen/recipe.rb +78 -0
- data/lib/kitchen/search_history.rb +33 -0
- data/lib/kitchen/selectors/base.rb +8 -0
- data/lib/kitchen/selectors/standard_1.rb +12 -0
- data/lib/kitchen/table_element.rb +36 -0
- data/lib/kitchen/table_element_enumerator.rb +13 -0
- data/lib/kitchen/term_element.rb +16 -0
- data/lib/kitchen/term_element_enumerator.rb +13 -0
- data/lib/kitchen/transliterations.rb +19 -0
- data/lib/kitchen/type_casting_element_enumerator.rb +23 -0
- data/lib/kitchen/utils.rb +19 -0
- data/lib/kitchen/version.rb +3 -0
- data/lib/locales/en.yml +21 -0
- data/lib/notes.md +9 -0
- data/openstax_kitchen.gemspec +39 -0
- data/tutorials/00/expected_baked.html +3 -0
- data/tutorials/00/raw.html +3 -0
- data/tutorials/00/solution_1.rb +7 -0
- data/tutorials/00/solution_2.rb +6 -0
- data/tutorials/01/expected_baked.html +66 -0
- data/tutorials/01/raw.html +62 -0
- data/tutorials/01/solution_1.rb +16 -0
- data/tutorials/01/solution_2.rb +24 -0
- data/tutorials/02/expected_baked.html +207 -0
- data/tutorials/02/raw.html +201 -0
- data/tutorials/02/solution_1.rb +29 -0
- data/tutorials/03/expected_baked.html +33 -0
- data/tutorials/03/raw.html +31 -0
- data/tutorials/03/solution_1.rb +16 -0
- data/tutorials/03/solution_2.rb +15 -0
- data/tutorials/04/expected_baked.html +36 -0
- data/tutorials/04/raw.html +36 -0
- data/tutorials/04/solution_1.rb +20 -0
- data/tutorials/04/solution_2.rb +25 -0
- data/tutorials/05/expected_baked.html +11 -0
- data/tutorials/05/raw.html +11 -0
- data/tutorials/05/solution_1.rb +9 -0
- data/tutorials/check_it +64 -0
- data/tutorials/setup_my_recipes +30 -0
- metadata +278 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
<div class="os-eob os-index-container " data-type="composite-page" data-uuid-key="index">
|
2
|
+
<h1 data-type="document-title">
|
3
|
+
<span class="os-text"><%= I18n.t(:eob_index_title) %></span>
|
4
|
+
</h1>
|
5
|
+
<div data-type="metadata" style="display: none;">
|
6
|
+
<h1 data-type="document-title" itemprop="name"><%= I18n.t(:eob_index_title) %></h1>
|
7
|
+
<%= @metadata_elements.paste %>
|
8
|
+
</div>
|
9
|
+
<% @index.sections.each do |section| %>
|
10
|
+
<div class="group-by">
|
11
|
+
<span class="group-label"><%= section.name %></span>
|
12
|
+
<% section.items.each do |item| %>
|
13
|
+
<div class="os-index-item">
|
14
|
+
<% item.terms.each_with_index do |term, ii| %>
|
15
|
+
<% if ii == 0 %>
|
16
|
+
<span class="os-term" group-by="<%= term.group_by %>"><%= term.text %></span>
|
17
|
+
<% else %>
|
18
|
+
<span class="os-index-link-separator">, </span>
|
19
|
+
<% end %>
|
20
|
+
<a class="os-term-section-link" href="#<%= term.id %>">
|
21
|
+
<span class="os-term-section"><%= term.page_title %></span>
|
22
|
+
</a>
|
23
|
+
<% end %>
|
24
|
+
</div>
|
25
|
+
<% end %>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Kitchen
|
2
|
+
module Directions
|
3
|
+
module BakeNotes
|
4
|
+
|
5
|
+
def self.v1(book:)
|
6
|
+
book.notes.each do |note|
|
7
|
+
title = note.title&.cut
|
8
|
+
|
9
|
+
note.replace_children(with:
|
10
|
+
<<~HTML
|
11
|
+
<div class="os-note-body">#{note.children}</div>
|
12
|
+
HTML
|
13
|
+
)
|
14
|
+
|
15
|
+
if title
|
16
|
+
if note.indicates_autogenerated_title?
|
17
|
+
note.prepend(child:
|
18
|
+
<<~HTML
|
19
|
+
<h3 class="os-title" data-type="title">
|
20
|
+
<span class="os-title-label">#{note.autogenerated_title}</span>
|
21
|
+
</h3>
|
22
|
+
HTML
|
23
|
+
)
|
24
|
+
|
25
|
+
title.name = "h4"
|
26
|
+
title.add_class("os-subtitle")
|
27
|
+
title.replace_children(with:
|
28
|
+
<<~HTML
|
29
|
+
<span class="os-subtitle-label">#{title.children}</span>
|
30
|
+
HTML
|
31
|
+
)
|
32
|
+
note.first!(".os-note-body").prepend(child: title.raw)
|
33
|
+
else
|
34
|
+
title.name = "h3"
|
35
|
+
title.add_class("os-title")
|
36
|
+
title.replace_children(with:
|
37
|
+
<<~HTML
|
38
|
+
<span data-type="" id="#{title.id}" class="os-title-label">#{title.children}</span>
|
39
|
+
HTML
|
40
|
+
)
|
41
|
+
title.remove_attribute("id")
|
42
|
+
note.prepend(child: title.raw)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
note.prepend(child:
|
46
|
+
<<~HTML
|
47
|
+
<h3 class="os-title" data-type="title">
|
48
|
+
<span class="os-title-label">#{note.autogenerated_title}</span>
|
49
|
+
</h3>
|
50
|
+
HTML
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Kitchen::Directions::BakeNumberedTable
|
2
|
+
class V1
|
3
|
+
|
4
|
+
def bake(table:, number:)
|
5
|
+
table.wrap(%Q(<div class="os-table">))
|
6
|
+
|
7
|
+
table_label = "#{I18n.t(:table_label)} #{number}"
|
8
|
+
table.document.pantry(name: :link_text).store table_label, label: table.id
|
9
|
+
|
10
|
+
if table.top_titled?
|
11
|
+
table.prepend(sibling:
|
12
|
+
<<~HTML
|
13
|
+
<div class="os-table-title">#{table.title}</div>
|
14
|
+
HTML
|
15
|
+
)
|
16
|
+
table.title_row.trash
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO extra spaces added here to match legacy implementation, but probably not meaningful?
|
20
|
+
new_summary = table_label + " "
|
21
|
+
new_caption = ""
|
22
|
+
|
23
|
+
if (caption = table.caption&.cut)
|
24
|
+
new_summary += caption.text
|
25
|
+
new_caption = <<~HTML
|
26
|
+
\n<span class="os-caption">#{caption.children}</span>
|
27
|
+
HTML
|
28
|
+
end
|
29
|
+
|
30
|
+
table[:summary] = new_summary
|
31
|
+
|
32
|
+
if !table.unnumbered?
|
33
|
+
table.append(sibling:
|
34
|
+
<<~HTML
|
35
|
+
<div class="os-caption-container">
|
36
|
+
<span class="os-title-label">#{I18n.t(:table_label)} </span>
|
37
|
+
<span class="os-number">#{number}</span>
|
38
|
+
<span class="os-divider"> </span>
|
39
|
+
<span class="os-divider"> </span>#{new_caption}
|
40
|
+
</div>
|
41
|
+
HTML
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Kitchen
|
2
|
+
module Directions
|
3
|
+
module BakeStepwise
|
4
|
+
|
5
|
+
def self.v1(book:)
|
6
|
+
book.search("ol.stepwise").each do |ol|
|
7
|
+
ol.remove_class("stepwise")
|
8
|
+
ol.add_class("os-stepwise")
|
9
|
+
|
10
|
+
ol.search("li").each_with_index do |li, ii|
|
11
|
+
li.replace_children(with:
|
12
|
+
<<~HTML
|
13
|
+
<span class="os-stepwise-content">#{li.children}</span>
|
14
|
+
HTML
|
15
|
+
)
|
16
|
+
li.prepend(child:
|
17
|
+
<<~HTML
|
18
|
+
<span class="os-stepwise-token">#{I18n.t(:stepwise_step_label)} #{ii+1}. </span>
|
19
|
+
HTML
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Kitchen
|
2
|
+
module Directions
|
3
|
+
module BakeToc
|
4
|
+
|
5
|
+
def self.v1(book:)
|
6
|
+
li_tags = book.body.element_children.map do |element|
|
7
|
+
case element
|
8
|
+
when ChapterElement
|
9
|
+
li_for_chapter(element)
|
10
|
+
when PageElement, CompositePageElement
|
11
|
+
li_for_page(element)
|
12
|
+
when CompositeChapterElement
|
13
|
+
li_for_composite_chapter(element)
|
14
|
+
end
|
15
|
+
end.compact.join("\n")
|
16
|
+
|
17
|
+
book.first!("nav").replace_children(with: <<~HTML
|
18
|
+
<h1 class="os-toc-title">Contents</h1>
|
19
|
+
<ol>
|
20
|
+
#{li_tags}
|
21
|
+
</ol>
|
22
|
+
HTML
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.li_for_composite_chapter(chapter)
|
27
|
+
pages = chapter.element_children.only(CompositePageElement)
|
28
|
+
|
29
|
+
<<~HTML
|
30
|
+
<li class="os-toc-composite-chapter" cnx-archive-shortid="" cnx-archive-uri="">
|
31
|
+
<a href="##{chapter.title.id}">
|
32
|
+
#{chapter.title.children.to_s}
|
33
|
+
</a>
|
34
|
+
<ol class="os-chapter">
|
35
|
+
#{pages.map{|page| li_for_page(page)}.join("\n")}
|
36
|
+
</ol>
|
37
|
+
</li>
|
38
|
+
HTML
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.li_for_chapter(chapter)
|
42
|
+
pages = chapter.element_children.only(PageElement, CompositePageElement)
|
43
|
+
|
44
|
+
<<~HTML
|
45
|
+
<li class="os-toc-chapter" cnx-archive-shortid="" cnx-archive-uri="">
|
46
|
+
<a href="##{chapter.title.id}">
|
47
|
+
<span class="os-number"><span class="os-part-text">Chapter </span>#{chapter.count_in(:book)}</span>
|
48
|
+
<span class="os-divider"> </span>
|
49
|
+
<span class="os-text" data-type="" itemprop="">#{chapter.title.first!(".os-text").text}</span>
|
50
|
+
</a>
|
51
|
+
<ol class="os-chapter">
|
52
|
+
#{pages.map{|page| li_for_page(page)}.join("\n")}
|
53
|
+
</ol>
|
54
|
+
</li>
|
55
|
+
HTML
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.li_for_page(page)
|
59
|
+
li_class =
|
60
|
+
if page.is_a?(PageElement)
|
61
|
+
if page.has_ancestor?(:chapter)
|
62
|
+
"os-toc-chapter-page"
|
63
|
+
elsif page.is_appendix?
|
64
|
+
"os-toc-appendix"
|
65
|
+
elsif page.is_preface?
|
66
|
+
"os-toc-preface"
|
67
|
+
else
|
68
|
+
raise "do not know what TOC class to use for page with classes #{page.classes}"
|
69
|
+
end
|
70
|
+
elsif page.is_a?(CompositePageElement)
|
71
|
+
if page.is_index?
|
72
|
+
"os-toc-index"
|
73
|
+
elsif page.has_ancestor?(:composite_chapter) || page.has_ancestor?(:chapter)
|
74
|
+
"os-toc-chapter-composite-page"
|
75
|
+
else
|
76
|
+
raise "do not know what TOC class to use for page with classes #{page.classes}"
|
77
|
+
end
|
78
|
+
else
|
79
|
+
raise(ArgumentError, "don't know how to put `#{page.class}` into the TOC")
|
80
|
+
end
|
81
|
+
|
82
|
+
title = page.title.copy
|
83
|
+
|
84
|
+
# The part text gets inserted as a child to the number span
|
85
|
+
part_text = title.first(".os-part-text")
|
86
|
+
number = title.first(".os-number")
|
87
|
+
if part_text && number
|
88
|
+
part_text = part_text.cut
|
89
|
+
number.prepend(child: part_text.paste)
|
90
|
+
end
|
91
|
+
|
92
|
+
<<~HTML
|
93
|
+
<li class="#{li_class}" cnx-archive-shortid="" cnx-archive-uri="#{page.id}">
|
94
|
+
<a href="##{page.id}">
|
95
|
+
#{title.element_children.copy.paste}
|
96
|
+
</a>
|
97
|
+
</li>
|
98
|
+
HTML
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
class Document
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_accessor :location
|
8
|
+
attr_reader :config
|
9
|
+
|
10
|
+
def_delegators :config, :selectors
|
11
|
+
def_delegators :@nokogiri_document, :to_xhtml, :to_s, :to_xml, :to_html
|
12
|
+
|
13
|
+
def initialize(nokogiri_document:, config: nil)
|
14
|
+
@nokogiri_document = nokogiri_document
|
15
|
+
@location = nil
|
16
|
+
@config = config || Config.new_default
|
17
|
+
@next_paste_count_for_id = {}
|
18
|
+
@id_copy_suffix = "_copy_"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns an enumerator that iterates over all children of this document
|
22
|
+
# that match the provided selector or XPath arguments.
|
23
|
+
#
|
24
|
+
# @param selector_or_xpath_args [Array<String>] CSS selectors or XPath arguments
|
25
|
+
# @return [ElementEnumerator]
|
26
|
+
#
|
27
|
+
def search(*selector_or_xpath_args)
|
28
|
+
selector_or_xpath_args = [selector_or_xpath_args].flatten
|
29
|
+
|
30
|
+
ElementEnumerator.new do |block|
|
31
|
+
nokogiri_document.search(*selector_or_xpath_args).each do |inner_node|
|
32
|
+
element = Kitchen::Element.new(node: inner_node,
|
33
|
+
document: self,
|
34
|
+
short_type: Utils.search_path_to_type(selector_or_xpath_args))
|
35
|
+
self.location = element
|
36
|
+
block.yield(element)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the document's clipboard with the given name.
|
42
|
+
#
|
43
|
+
# @param name [Symbol, String] the name of the clipboard. String values are
|
44
|
+
# converted to symbols.
|
45
|
+
# @return [Clipboard]
|
46
|
+
#
|
47
|
+
def clipboard(name: :default)
|
48
|
+
(@clipboards ||= {})[name.to_sym] ||= Clipboard.new
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the document's pantry with the given name.
|
52
|
+
#
|
53
|
+
# @param name [Symbol, String] the name of the pantry. String values are
|
54
|
+
# converted to symbols.
|
55
|
+
# @return [Pantry]
|
56
|
+
#
|
57
|
+
def pantry(name: :default)
|
58
|
+
(@pantries ||= {})[name.to_sym] ||= Pantry.new
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the document's counter with the given name.
|
62
|
+
#
|
63
|
+
# @param name [Symbol, String] the name of the counter. String values are
|
64
|
+
# converted to symbols.
|
65
|
+
# @return [Counter]
|
66
|
+
#
|
67
|
+
def counter(name)
|
68
|
+
(@counters ||= {})[name.to_sym] ||= Counter.new
|
69
|
+
end
|
70
|
+
|
71
|
+
# Create a new Element
|
72
|
+
#
|
73
|
+
# TODO don't know if we need this
|
74
|
+
#
|
75
|
+
# @param name [String] the tag name
|
76
|
+
# @param args [Array<String, Hash>]
|
77
|
+
#
|
78
|
+
# @example div with a class
|
79
|
+
# create_element("div", class: "foo") #=> <div class="foo"></div>
|
80
|
+
# @example div with some content and a class
|
81
|
+
# cretae_element("div", "contents", class: "foo") #=> <div class="foo">contents</div>
|
82
|
+
# @example div created by block
|
83
|
+
# create_element("div") {|elem| elem['class'] = 'foo'} #=> <div class="foo"></div>
|
84
|
+
#
|
85
|
+
# @return [Element]
|
86
|
+
#
|
87
|
+
def create_element(name, *args, &block)
|
88
|
+
Kitchen::Element.new(
|
89
|
+
node: @nokogiri_document.create_element(name, *args, &block),
|
90
|
+
document: self,
|
91
|
+
short_type: "created_element_#{SecureRandom.hex(4)}"
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def create_element_from_string(string)
|
96
|
+
Kitchen::Element.new(
|
97
|
+
node: @nokogiri_document.create_element("div"),
|
98
|
+
document: self,
|
99
|
+
short_type: "created_element_#{SecureRandom.hex(4)}"
|
100
|
+
).element_children.first
|
101
|
+
end
|
102
|
+
|
103
|
+
def record_id_copied(id)
|
104
|
+
return if id.blank?
|
105
|
+
@next_paste_count_for_id[id] ||= 1
|
106
|
+
end
|
107
|
+
|
108
|
+
def modified_id_to_paste(original_id)
|
109
|
+
return nil if original_id.nil?
|
110
|
+
return "" if original_id.blank?
|
111
|
+
|
112
|
+
count = next_count_for_pasted_id(original_id)
|
113
|
+
|
114
|
+
# A count of 0 means the element was cut and this is the first paste, do not
|
115
|
+
# modify the ID; otherwise, use the uniquified ID.
|
116
|
+
if count == 0
|
117
|
+
original_id
|
118
|
+
else
|
119
|
+
"#{original_id}#{@id_copy_suffix}#{count}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns the underlying Nokogiri Document object
|
124
|
+
#
|
125
|
+
# @return [Nokogiri::XML::Document]
|
126
|
+
def raw
|
127
|
+
@nokogiri_document
|
128
|
+
end
|
129
|
+
|
130
|
+
protected
|
131
|
+
|
132
|
+
def next_count_for_pasted_id(id)
|
133
|
+
return if id.blank?
|
134
|
+
(@next_paste_count_for_id[id] ||= 0).tap do
|
135
|
+
@next_paste_count_for_id[id] += 1
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
attr_reader :nokogiri_document
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|