caramelize 1.1.1 → 1.2.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +11 -0
  3. data/.github/workflows/main.yml +48 -0
  4. data/.rubocop.yml +29 -0
  5. data/Gemfile +12 -0
  6. data/Gemfile.lock +37 -25
  7. data/README.md +2 -3
  8. data/Rakefile +3 -1
  9. data/bin/caramelize +6 -5
  10. data/caramelize.gemspec +14 -19
  11. data/lib/caramelize/caramel.rb +32 -32
  12. data/lib/caramelize/content_transferer.rb +55 -32
  13. data/lib/caramelize/database_connector.rb +8 -8
  14. data/lib/caramelize/filter_processor.rb +2 -0
  15. data/lib/caramelize/filters/add_newline_to_page_end.rb +22 -0
  16. data/lib/caramelize/filters/camel_case_to_wiki_links.rb +26 -0
  17. data/lib/caramelize/filters/remove_table_tab_line_endings.rb +3 -2
  18. data/lib/caramelize/filters/swap_wiki_links.rb +5 -3
  19. data/lib/caramelize/filters/wikka_to_markdown.rb +26 -20
  20. data/lib/caramelize/health_check.rb +6 -68
  21. data/lib/caramelize/health_checks/home_page_check.rb +23 -0
  22. data/lib/caramelize/health_checks/orphaned_pages_check.rb +56 -0
  23. data/lib/caramelize/health_checks/page.rb +28 -0
  24. data/lib/caramelize/input_wiki/redmine_wiki.rb +18 -15
  25. data/lib/caramelize/input_wiki/wiki.rb +11 -5
  26. data/lib/caramelize/input_wiki/wikkawiki.rb +23 -14
  27. data/lib/caramelize/output_wiki/gollum.rb +10 -10
  28. data/lib/caramelize/page.rb +14 -10
  29. data/lib/caramelize/services/page_builder.rb +11 -8
  30. data/lib/caramelize/version.rb +3 -1
  31. data/lib/caramelize.rb +5 -0
  32. data/spec/lib/caramelize/content_transferer_spec.rb +3 -1
  33. data/spec/lib/caramelize/filter_processor_spec.rb +9 -4
  34. data/spec/lib/caramelize/filters/add_newline_to_page_end_spec.rb +29 -0
  35. data/spec/lib/caramelize/filters/camel_case_to_wiki_links_spec.rb +46 -0
  36. data/spec/lib/caramelize/filters/remove_table_tab_line_endings_spec.rb +19 -12
  37. data/spec/lib/caramelize/filters/swap_wiki_links_spec.rb +19 -14
  38. data/spec/lib/caramelize/filters/wikka2markdown_spec.rb +265 -0
  39. data/spec/lib/caramelize/input_wiki/wiki_spec.rb +24 -23
  40. data/spec/lib/caramelize/output_wiki/gollum_spec.rb +36 -34
  41. data/spec/lib/caramelize/page_spec.rb +34 -26
  42. data/spec/lib/caramelize/services/page_builder_spec.rb +41 -0
  43. data/spec/spec_helper.rb +4 -2
  44. metadata +19 -121
  45. data/.travis.yml +0 -5
  46. data/spec/lib/caramelize/filters/wikka_to_markdown_spec.rb +0 -198
  47. data/spec/lib/caramelize/services/page_builder.rb +0 -29
@@ -1,8 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Caramelize
2
4
  class Page
3
-
4
- attr_accessor :title, :body, :id, :markup, :latest, :time, :message,
5
- :author, :author_name
5
+ attr_accessor :title, :body, :id, :markup, :latest, :time, :message, :author
6
6
 
7
7
  def initialize(page = {})
8
8
  @id = page[:id]
@@ -13,20 +13,18 @@ module Caramelize
13
13
  @time = page.fetch(:time, Time.now)
14
14
  @message = page.fetch(:message, '')
15
15
  @author = page[:author]
16
- @author_name = page[:author_name]
17
16
  end
18
17
 
19
18
  def author_email
20
- author.email
19
+ author[:email]
21
20
  end
22
21
 
23
22
  def author_name
24
- author.name
23
+ author[:name]
25
24
  end
26
25
 
27
- def author
28
- @author ||= OpenStruct.new(name: @author_name || "Caramelize",
29
- email: "mail@example.com")
26
+ def author # rubocop:todo Lint/DuplicateMethods
27
+ @author ||= { name: 'Caramelize', email: 'mail@example.com' }
30
28
  end
31
29
 
32
30
  def latest?
@@ -35,7 +33,12 @@ module Caramelize
35
33
 
36
34
  def path
37
35
  return @title unless @title.index('/')
38
- @title.split('/').first + '/' + @title.split('/').last.downcase
36
+
37
+ "#{title_pieces.first}/#{title_pieces.last.downcase}"
38
+ end
39
+
40
+ def title_pieces
41
+ @title.split('/')
39
42
  end
40
43
 
41
44
  def set_latest
@@ -48,6 +51,7 @@ module Caramelize
48
51
 
49
52
  def commit_message
50
53
  return "Edit in page #{title}" if message.empty?
54
+
51
55
  message
52
56
  end
53
57
  end
@@ -1,17 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Caramelize
2
4
  module Services
3
5
  class PageBuilder
6
+ HEADLINE = "## Overview of namespaces\n"
7
+
4
8
  def self.build_namespace_overview(namespaces)
5
- body = "## Overview of namespaces\n\n"
9
+ # TODO: change wiki as configurable default home
10
+ # TODO support other markup syntaxes
6
11
 
7
- namespaces.each do |namespace|
8
- # TODO change wiki as configurable default home
9
- # TODO support other markup syntaxes
10
- body << "* [[#{namespace[:name]}|#{namespace[:identifier]}/wiki]] \n"
11
- end
12
+ body = namespaces.map do |namespace|
13
+ "* [[#{namespace[:name]}|#{namespace[:identifier]}/wiki]]"
14
+ end.prepend(HEADLINE).join(" \n")
12
15
 
13
- Page.new(title: "Home",
14
- body: body,
16
+ Page.new(title: 'Home',
17
+ body:,
15
18
  message: 'Create Namespace Overview',
16
19
  latest: true)
17
20
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Caramelize
2
- VERSION = '1.1.1'
4
+ VERSION = '1.2.1'
3
5
  end
data/lib/caramelize.rb CHANGED
@@ -1,9 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'caramelize/version'
2
4
  require 'caramelize/page'
3
5
  require 'caramelize/content_transferer'
4
6
  require 'caramelize/filter_processor'
5
7
  require 'caramelize/database_connector'
6
8
  require 'caramelize/health_check'
9
+ require 'caramelize/health_checks/home_page_check'
10
+ require 'caramelize/health_checks/orphaned_pages_check'
11
+ require 'caramelize/health_checks/page'
7
12
  require 'caramelize/output_wiki/gollum'
8
13
  require 'caramelize/services/page_builder'
9
14
  require 'caramelize/input_wiki/wiki'
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Caramelize::ContentTransferer do
4
6
  describe '#execute' do
5
7
  context 'with original_wiki' do
6
- pending
8
+ pending('test full transfer')
7
9
  end
8
10
  end
9
11
  end
@@ -1,20 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Caramelize::FilterProcessor do
6
+ subject(:processor) { described_class.new(input_wiki) }
7
+
4
8
  let(:filters) { [] }
5
- let(:input_wiki) { double(filters: filters) }
9
+ let(:input_wiki) { double(filters:) } # rubocop:todo RSpec/VerifiedDoubles
6
10
  let(:body) { 'body' }
7
- subject(:processor) { described_class.new(input_wiki) }
8
11
 
9
- class ReverseFilter
12
+ # rubocop:todo RSpec/LeakyConstantDeclaration
13
+ class ReverseFilter # rubocop:todo Lint/ConstantDefinitionInBlock, RSpec/LeakyConstantDeclaration
10
14
  def initialize(body)
11
15
  @body = body
12
16
  end
13
17
 
14
18
  def run
15
- @body.reverse
19
+ @body.reverse # rubocop:todo RSpec/InstanceVariable
16
20
  end
17
21
  end
22
+ # rubocop:enable RSpec/LeakyConstantDeclaration
18
23
 
19
24
  describe '#run' do
20
25
  context 'without any filters' do
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ # rubocop:todo RSpec/SpecFilePathFormat
6
+ describe Caramelize::Filter::AddNewlineToPageEnd do # rubocop:todo RSpec/FilePath, RSpec/SpecFilePathFormat
7
+ # rubocop:enable RSpec/SpecFilePathFormat
8
+ describe '#run' do
9
+ subject(:run) { filter.run }
10
+
11
+ let(:filter) { described_class.new(body) }
12
+
13
+ context 'with newline on body end' do
14
+ let(:body) { "Here is a sample body\n" }
15
+
16
+ it 'adds no newline character' do
17
+ expect(run).to eq "Here is a sample body\n"
18
+ end
19
+ end
20
+
21
+ context 'without newline on body end' do
22
+ let(:body) { 'Here is a sample body' }
23
+
24
+ it 'adds newline character' do
25
+ expect(run).to eq "Here is a sample body\n"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ # rubocop:todo RSpec/SpecFilePathFormat
6
+ describe Caramelize::CamelCaseToWikiLinks do # rubocop:todo RSpec/FilePath, RSpec/SpecFilePathFormat
7
+ # rubocop:enable RSpec/SpecFilePathFormat
8
+ describe '#run' do
9
+ subject(:run) { filter.run }
10
+
11
+ let(:filter) { described_class.new(body) }
12
+
13
+ context 'with camel case text' do
14
+ let(:body) { 'Hier ein CamelCaseExample, bitte [[DankeDanke]]' }
15
+
16
+ it 'does wiki link' do
17
+ expect(run).to eq 'Hier ein [[CamelCaseExample]], bitte [[DankeDanke]]'
18
+ end
19
+ end
20
+
21
+ context 'with camel case text downcased' do
22
+ let(:body) { 'Hier ein camelCaseExample, bitte [[DankeDanke]]' }
23
+
24
+ it 'does not to wiki link' do
25
+ expect(run).to eq 'Hier ein camelCaseExample, bitte [[DankeDanke]]'
26
+ end
27
+ end
28
+
29
+ context 'with camel case text at document end' do
30
+ let(:body) { 'Hier ein CamelCaseExample' }
31
+
32
+ # NOTE: this is sortof expected behavior - a wiki page should end on a newline in which case this does not happen
33
+ it 'cuts last character' do
34
+ expect(run).to eq 'Hier ein [[CamelCaseExampl]]e'
35
+ end
36
+ end
37
+
38
+ context 'with camel case text at document end with newline' do
39
+ let(:body) { "Hier ein CamelCaseExample\n" }
40
+
41
+ it 'does wiki link' do
42
+ expect(run).to eq "Hier ein [[CamelCaseExample]]\n"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,15 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe Caramelize::RemoveTableTabLineEndings do
5
+ # rubocop:todo RSpec/SpecFilePathFormat
6
+ describe Caramelize::RemoveTableTabLineEndings do # rubocop:todo RSpec/FilePath, RSpec/SpecFilePathFormat
7
+ # rubocop:enable RSpec/SpecFilePathFormat
8
+ subject(:run) { filter.run }
9
+
4
10
  let(:filter) { described_class.new(body) }
5
- subject { filter.run}
6
11
 
7
12
  describe '#run' do
8
- context 'table with tabs at unix line-endings' do
13
+ context 'table with tabs at unix line-endings' do # rubocop:todo RSpec/ContextWording
9
14
  let(:body) { "cell1\t|cell2\t|\t\t\n" }
10
15
 
11
16
  it 'removes tabs at end of line' do
12
- is_expected.to eq "cell1\t|cell2\t|\n"
17
+ expect(run).to eq "cell1\t|cell2\t|\n"
13
18
  end
14
19
  end
15
20
 
@@ -17,24 +22,26 @@ describe Caramelize::RemoveTableTabLineEndings do
17
22
  let(:body) { "cell1\t|cell2\t|\t \n" }
18
23
 
19
24
  it 'removes spaces at end of line' do
20
- is_expected.to eq "cell1\t|cell2\t|\n"
25
+ expect(run).to eq "cell1\t|cell2\t|\n"
21
26
  end
22
27
 
23
- context 'replace in full file' do
24
- let(:body) { File.open(File.join(['spec', 'fixtures', 'markup', 'table-tab-line-endings-input.textile']), 'r').read }
28
+ context 'replace in full file' do # rubocop:todo RSpec/ContextWording
29
+ let(:body) do
30
+ File.read(File.join(['spec', 'fixtures', 'markup', 'table-tab-line-endings-input.textile']))
31
+ end
25
32
 
26
33
  it 'returns as expected' do
27
- output_text = File.open(File.join(['spec', 'fixtures', 'markup', 'table-tab-line-endings-output.textile']), 'r').read
28
- is_expected.to eq output_text
34
+ output_text = File.read(File.join(['spec', 'fixtures', 'markup', 'table-tab-line-endings-output.textile']))
35
+ expect(run).to eq output_text
29
36
  end
30
37
  end
31
38
  end
32
39
 
33
- context 'table with tabs at windows line-endings' do
40
+ context 'with table having tabs at windows line-endings' do
34
41
  let(:body) { "cell1\t|cell2\t|\t\t\r\n" }
35
42
 
36
43
  it 'removes tabs at end of line' do
37
- is_expected.to eq "cell1\t|cell2\t|\n"
44
+ expect(run).to eq "cell1\t|cell2\t|\n"
38
45
  end
39
46
  end
40
47
 
@@ -42,7 +49,7 @@ describe Caramelize::RemoveTableTabLineEndings do
42
49
  let(:body) { "cell1\t|cell2\t|\t \r\n" }
43
50
 
44
51
  it 'removes spaces at end of line' do
45
- is_expected.to eq "cell1\t|cell2\t|\n"
52
+ expect(run).to eq "cell1\t|cell2\t|\n"
46
53
  end
47
54
  end
48
55
  end
@@ -1,47 +1,52 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe Caramelize::SwapWikiLinks do
5
+ # rubocop:todo RSpec/SpecFilePathFormat
6
+ describe Caramelize::SwapWikiLinks do # rubocop:todo RSpec/FilePath, RSpec/SpecFilePathFormat
7
+ # rubocop:enable RSpec/SpecFilePathFormat
4
8
  describe '#run' do
9
+ subject(:run) { filter.run }
10
+
5
11
  let(:filter) { described_class.new(body) }
6
- subject { filter.run }
7
12
 
8
- context 'wiki link with title' do
13
+ context 'with wiki link with title' do
9
14
  let(:body) { '[[statistics|Driver & Team Statistics]]' }
10
15
 
11
16
  it 'swaps title and target' do
12
- is_expected.to eq '[[Driver & Team Statistics|statistics]]'
17
+ expect(run).to eq '[[Driver & Team Statistics|statistics]]'
13
18
  end
14
19
  end
15
20
 
16
- context 'wiki title with spaces' do
21
+ context 'with wiki title with spaces' do
17
22
  let(:body) { '[[Release 1 0]]' }
18
23
 
19
24
  it 'replaces space with dashes' do
20
- is_expected.to eq '[[Release 1 0|release_1_0]]'
25
+ expect(run).to eq '[[Release 1 0|release_1_0]]'
21
26
  end
22
27
  end
23
28
 
24
- context 'wiki title with dashes' do
29
+ context 'with wiki title with dashes' do
25
30
  let(:body) { '[[Release-1.0]]' }
26
31
 
27
32
  it 'removes dots' do
28
- is_expected.to eq '[[Release-1.0|release-10]]'
33
+ expect(run).to eq '[[Release-1.0|release-10]]'
29
34
  end
30
35
  end
31
36
 
32
- context 'wiki link with spaces and without title' do
37
+ context 'with wiki link with spaces and without title' do
33
38
  let(:body) { '[[Intra wiki link]]' }
34
39
 
35
40
  it 'simples link to hyperlink' do
36
- is_expected.to eq '[[Intra wiki link|intra_wiki_link]]'
41
+ expect(run).to eq '[[Intra wiki link|intra_wiki_link]]'
37
42
  end
38
43
 
39
- context 'replace in full file' do
40
- let(:body) { File.open(File.join(['spec', 'fixtures', 'markup', 'swap-links-input.textile']), 'r').read }
44
+ context 'with replace in full file' do
45
+ let(:body) { File.read(File.join(['spec', 'fixtures', 'markup', 'swap-links-input.textile'])) }
41
46
 
42
47
  it 'returns as expected' do
43
- output_text = File.open(File.join(['spec', 'fixtures', 'markup', 'swap-links-output.textile']), 'r').read
44
- is_expected.to eq output_text
48
+ output_text = File.read(File.join(['spec', 'fixtures', 'markup', 'swap-links-output.textile']))
49
+ expect(run).to eq output_text
45
50
  end
46
51
  end
47
52
  end
@@ -0,0 +1,265 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ # rubocop:todo RSpec/SpecFilePathFormat
6
+ describe Caramelize::Wikka2Markdown do # rubocop:todo RSpec/FilePath, RSpec/SpecFilePathFormat
7
+ # rubocop:enable RSpec/SpecFilePathFormat
8
+ let(:filter) { described_class.new(body) }
9
+
10
+ describe '#run' do
11
+ subject { filter.run }
12
+
13
+ xcontext 'when keep line breaks' do # rubocop:todo RSpec/PendingWithoutReason
14
+ let(:body) { "line1\nline2" }
15
+
16
+ it { is_expected.to eq "line1 \nline2" }
17
+ end
18
+
19
+ context 'when headline h1' do
20
+ let(:body) { '======Headline======' }
21
+
22
+ it { is_expected.to eq '# Headline' }
23
+ end
24
+
25
+ context 'when headline h2' do
26
+ let(:body) { '=====Headline=====' }
27
+
28
+ it { is_expected.to eq '## Headline' }
29
+ end
30
+
31
+ context 'when headline h3' do
32
+ let(:body) { '====Headline====' }
33
+
34
+ it { is_expected.to eq '### Headline' }
35
+ end
36
+
37
+ context 'when headline h4' do
38
+ let(:body) { '===Headline===' }
39
+
40
+ it { is_expected.to eq '#### Headline' }
41
+ end
42
+
43
+ context 'when headline h5' do
44
+ let(:body) { '==Headline==' }
45
+
46
+ it { is_expected.to eq '##### Headline' }
47
+ end
48
+
49
+ context 'when bold' do
50
+ let(:body) { '**Text is bold**' }
51
+
52
+ it { is_expected.to eq '**Text is bold**' }
53
+ end
54
+
55
+ context 'when italic' do
56
+ let(:body) { '//Text is italic//' }
57
+
58
+ it { is_expected.to eq '*Text is italic*' }
59
+ end
60
+
61
+ context 'when underline' do
62
+ let(:body) { '__Text is underlined__' }
63
+
64
+ it { is_expected.to eq '<u>Text is underlined</u>' }
65
+ end
66
+
67
+ context 'when line break' do
68
+ let(:body) { 'Text is---\nbroken to two lines.' }
69
+
70
+ it { is_expected.to eq 'Text is \nbroken to two lines.' }
71
+ end
72
+
73
+ context 'when unordered list entry' do
74
+ context 'with tab based' do
75
+ let(:body) { "\t-unordered list entry" }
76
+
77
+ it { is_expected.to eq '- unordered list entry' }
78
+ end
79
+
80
+ context 'with tabs' do
81
+ let(:body) { '~-unordered list entry' }
82
+
83
+ it { is_expected.to eq '- unordered list entry' }
84
+ end
85
+
86
+ context 'with spaces' do
87
+ let(:body) { ' -unordered list entry' }
88
+
89
+ it { is_expected.to eq '- unordered list entry' }
90
+ end
91
+
92
+ context 'with tab based with space' do
93
+ let(:body) { "\t- unordered list entry" }
94
+
95
+ it { is_expected.to eq '- unordered list entry' }
96
+ end
97
+
98
+ context 'with another tab based with space' do
99
+ let(:body) { '~- unordered list entry' }
100
+
101
+ it { is_expected.to eq '- unordered list entry' }
102
+ end
103
+
104
+ context 'with space based with space' do
105
+ let(:body) { ' - unordered list entry' }
106
+
107
+ it { is_expected.to eq '- unordered list entry' }
108
+ end
109
+ end
110
+
111
+ context 'when ordered list entry' do
112
+ context 'without space' do
113
+ let(:body) { '~1)ordered list entry' }
114
+
115
+ it { is_expected.to eq '1. ordered list entry' }
116
+ end
117
+
118
+ context 'with space' do
119
+ let(:body) { '~1) ordered list entry' }
120
+
121
+ it { is_expected.to eq '1. ordered list entry' }
122
+ end
123
+ end
124
+
125
+ context 'when wikilink' do
126
+ context 'with only url' do
127
+ let(:body) { '[[LemmaLemma]]' }
128
+
129
+ it { is_expected.to eq '[[LemmaLemma]]' }
130
+ end
131
+
132
+ context 'with only url sklfs' do
133
+ let(:body) { "\n [[ComunitySiteIdeas]] \n" }
134
+
135
+ it { is_expected.to eq "\n [[ComunitySiteIdeas]] \n" }
136
+ end
137
+
138
+ context 'with url and pipe title' do
139
+ let(:body) { '[[SandBox|Test your formatting skills]]' }
140
+
141
+ it { is_expected.to eq '[[Test your formatting skills|SandBox]]' }
142
+ end
143
+
144
+ context 'with url and title' do
145
+ let(:body) { '[[SandBox Test your formatting skills]]' }
146
+
147
+ it { is_expected.to eq '[[Test your formatting skills|SandBox]]' }
148
+ end
149
+ end
150
+
151
+ context 'when hyperlink' do
152
+ context 'with only url' do
153
+ let(:body) { '[[http://target]]' }
154
+
155
+ it { is_expected.to eq '<http://target>' }
156
+ end
157
+
158
+ context 'with url with title' do
159
+ let(:body) { '[[http://target Title]]' }
160
+
161
+ it { is_expected.to eq '[Title](http://target)' }
162
+ end
163
+
164
+ context 'with url with title and special characters' do
165
+ let(:body) { '- [[http://www.sourcepole.com/sources/programming/cpp/cppqref.html C++ Syntax Reference]]' }
166
+
167
+ it { is_expected.to eq '- [C++ Syntax Reference](http://www.sourcepole.com/sources/programming/cpp/cppqref.html)' }
168
+ end
169
+
170
+ context 'with url with pipe' do
171
+ let(:body) { '[[http://target|Title]]' }
172
+
173
+ it { is_expected.to eq '[Title](http://target)' }
174
+ end
175
+ end
176
+
177
+ context 'when inline code' do
178
+ let(:body) { 'Code: %%Hello World%% // done' }
179
+
180
+ it { is_expected.to eq 'Code: `Hello World` // done' }
181
+ end
182
+
183
+ context 'when code block' do
184
+ let(:body) do
185
+ <<~CPP
186
+ Text before
187
+
188
+ %%
189
+ std::cin >> input;
190
+ ++stat[input];
191
+ %%
192
+
193
+ Text after
194
+
195
+ %%
196
+ std::cin >> input;
197
+ ++stat[input];
198
+ %%
199
+
200
+ CPP
201
+ end
202
+ let(:expected_result) do
203
+ <<~CPP
204
+ Text before
205
+
206
+ ```
207
+ std::cin >> input;
208
+ ++stat[input];
209
+ ```
210
+
211
+ Text after
212
+
213
+ ```
214
+ std::cin >> input;
215
+ ++stat[input];
216
+ ```
217
+
218
+ CPP
219
+ end
220
+
221
+ it { is_expected.to eq expected_result }
222
+ end
223
+
224
+ context 'when code block with language' do
225
+ let(:body) do
226
+ <<~CPP
227
+ Text before
228
+
229
+ %%(php)
230
+ std::cin >> input;
231
+ ++stat[input];
232
+ %%
233
+
234
+ Text after
235
+
236
+ %%(java)
237
+ std::cin >> input;
238
+ ++stat[input];
239
+ %%
240
+
241
+ CPP
242
+ end
243
+ let(:expected_result) do
244
+ <<~CPP
245
+ Text before
246
+
247
+ ```php
248
+ std::cin >> input;
249
+ ++stat[input];
250
+ ```
251
+
252
+ Text after
253
+
254
+ ```java
255
+ std::cin >> input;
256
+ ++stat[input];
257
+ ```
258
+
259
+ CPP
260
+ end
261
+
262
+ it { is_expected.to eq expected_result }
263
+ end
264
+ end
265
+ end