emcee 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/emcee.rb +4 -4
  3. data/lib/emcee/compressors/html_compressor.rb +11 -42
  4. data/lib/emcee/helpers/{action_view/asset_tag_helper.rb → asset_tag_helper.rb} +0 -0
  5. data/lib/emcee/helpers/{action_view/asset_url_helper.rb → asset_url_helper.rb} +0 -0
  6. data/lib/emcee/helpers/{sprockets/view_helpers.rb → sprockets_helper.rb} +0 -0
  7. data/lib/emcee/loose_assets.rb +19 -0
  8. data/lib/emcee/processors/directive_processor.rb +33 -0
  9. data/lib/emcee/processors/import_processor.rb +39 -0
  10. data/lib/emcee/processors/script_processor.rb +67 -0
  11. data/lib/emcee/processors/stylesheet_processor.rb +90 -0
  12. data/lib/emcee/railtie.rb +23 -27
  13. data/lib/emcee/version.rb +1 -1
  14. data/test/compressors_test.rb +1 -1
  15. data/test/dummy/app/assets/elements/application.html +1 -0
  16. data/test/dummy/app/assets/elements/compile/test5.css.scss +5 -0
  17. data/test/dummy/app/assets/elements/compile/test5.html +2 -0
  18. data/test/dummy/log/development.log +120 -0
  19. data/test/dummy/log/test.log +20934 -0
  20. data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  21. data/test/dummy/tmp/cache/assets/test/sprockets/1b8013559a887e8b8d91472ef246fef9 +0 -0
  22. data/test/dummy/tmp/cache/assets/test/sprockets/1e24025f59396708b3bb44543bed32fc +0 -0
  23. data/test/dummy/tmp/cache/assets/test/sprockets/219d0afb67879a67bae32b4fe4c708ac +0 -0
  24. data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  25. data/test/dummy/tmp/cache/assets/test/sprockets/2f90dac85033dad7b068860c3f6b7b27 +0 -0
  26. data/test/dummy/tmp/cache/assets/test/sprockets/32cae461a9446107294c8a0230f5080c +0 -0
  27. data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  28. data/test/dummy/tmp/cache/assets/test/sprockets/4fd1effec4d6579ba9d4f03ed156a15b +0 -0
  29. data/test/dummy/tmp/cache/assets/test/sprockets/6c9d8a21af4539e19a3462e79ac4d70c +0 -0
  30. data/test/dummy/tmp/cache/assets/test/sprockets/a69c3d00e22ad6c0d6ece35c9fd5f316 +0 -0
  31. data/test/dummy/tmp/cache/assets/test/sprockets/af6ba4ae23c6790e0f474b01ceee8dd9 +0 -0
  32. data/test/dummy/tmp/cache/assets/test/sprockets/cf517b62bd978b748afe38d5beb317de +0 -0
  33. data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  34. data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  35. data/test/dummy/tmp/cache/assets/test/sprockets/df6cfcc50da209231a7d9e140e5bafdc +0 -0
  36. data/test/dummy/tmp/cache/assets/test/sprockets/e0949aa3dcdcab5f8b45d30e26f6ddd2 +0 -0
  37. data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  38. data/test/dummy/tmp/cache/assets/test/sprockets/ffd4adb86602a60c7fcedd5d472166d3 +0 -0
  39. data/test/{controllers_test.rb → dummy_app_integration_test.rb} +7 -4
  40. data/test/processors_test.rb +45 -11
  41. metadata +34 -12
  42. data/lib/emcee/helpers/sprockets/compressing_helpers.rb +0 -35
  43. data/lib/emcee/processors/html_processor.rb +0 -84
  44. data/lib/emcee/processors/processor_includes.rb +0 -111
  45. data/test/emcee_test.rb +0 -7
@@ -1,10 +1,10 @@
1
1
  require 'test_helper'
2
2
  require 'action_controller'
3
3
 
4
- class ControllersTest < ActionController::TestCase
4
+ class DummyAppIntegrationTest < ActionController::TestCase
5
5
  tests DummyController
6
6
 
7
- test "should get index" do
7
+ test "should succesfully load the app and show index" do
8
8
  get :index
9
9
  assert_response :success
10
10
  end
@@ -22,13 +22,16 @@ class ControllersTest < ActionController::TestCase
22
22
  # To test the contents of our compiled application.html, we have a custom route
23
23
  # and controller action. The controller action renders the compiled file as a
24
24
  # json response, which we can test against here.
25
- test "the test files should get compiled and concatenated" do
25
+ test "the test files should get concatenated" do
26
26
  get :assets
27
- assert_response :success
28
27
  assert_equal @response.body, <<-EOS
29
28
  <script>var life = "is good";
30
29
  </script>
31
30
  <p>test4</p>
31
+ <style>p {
32
+ color: red; }
33
+ </style>
34
+ <p>compiled scss</p>
32
35
  <style>p {
33
36
  color: pink;
34
37
  }
@@ -1,17 +1,34 @@
1
1
  require 'test_helper'
2
+ require 'emcee/processors/import_processor'
3
+ require 'emcee/processors/script_processor'
4
+ require 'emcee/processors/stylesheet_processor'
2
5
 
3
- # Testing a class that inherits from Sprockets::DirectiveProcessor is difficult,
4
- # so we've split out the methods we want to test into a module, and we'll include
5
- # them here in a stub class.
6
- class ProcessorStub
7
- include Emcee::Processors::Includes
6
+ class ScriptProcessorStub < Emcee::ScriptProcessor
7
+ def read_file(path)
8
+ "/* contents */"
9
+ end
10
+ end
8
11
 
9
- private
12
+ class StylesheetProcessorStub < Emcee::StylesheetProcessor
10
13
  def read_file(path)
11
14
  "/* contents */"
12
15
  end
13
16
  end
14
17
 
18
+ class StylesheetSassProcessorStub < Emcee::StylesheetProcessor
19
+ def read_file(path)
20
+ "$color: red; p { color: $color; }"
21
+ end
22
+
23
+ def sass?(path)
24
+ true
25
+ end
26
+
27
+ def get_sass_content(path)
28
+ super(path).gsub(/\n\s?/, "")
29
+ end
30
+ end
31
+
15
32
  # Create a stub of Sprocket's Context class, so we can test if we're 'requiring'
16
33
  # assets correctly.
17
34
  class ContextStub
@@ -28,7 +45,6 @@ end
28
45
 
29
46
  class ProcessorsTest < ActiveSupport::TestCase
30
47
  setup do
31
- @processor = ProcessorStub.new
32
48
  @context = ContextStub.new
33
49
  @directory = "/dir"
34
50
  @body = %q{
@@ -40,10 +56,11 @@ class ProcessorsTest < ActiveSupport::TestCase
40
56
  end
41
57
 
42
58
  test "processing imports should work" do
43
- processed = @processor.process_imports(@body, @context, @directory)
59
+ processor = Emcee::ImportProcessor.new
60
+ processed = processor.process(@context, @body, @directory)
61
+
44
62
  assert_equal 1, @context.assets.length
45
63
  assert_equal "/dir/test.html", @context.assets[0]
46
-
47
64
  assert_equal processed, %q{
48
65
  <link rel="stylesheet" href="test.css">
49
66
  <script src="test.js"></script>
@@ -52,7 +69,9 @@ class ProcessorsTest < ActiveSupport::TestCase
52
69
  end
53
70
 
54
71
  test "processing stylesheets should work" do
55
- processed = @processor.process_stylesheets(@body, @directory)
72
+ processor = StylesheetProcessorStub.new
73
+ processed = processor.process(@context, @body, @directory)
74
+
56
75
  assert_equal processed, %q{
57
76
  <link rel="import" href="test.html">
58
77
  <style>/* contents */
@@ -63,7 +82,9 @@ class ProcessorsTest < ActiveSupport::TestCase
63
82
  end
64
83
 
65
84
  test "processing scripts should work" do
66
- processed = @processor.process_scripts(@body, @directory)
85
+ processor = ScriptProcessorStub.new
86
+ processed = processor.process(@context, @body, @directory)
87
+
67
88
  assert_equal processed, %q{
68
89
  <link rel="import" href="test.html">
69
90
  <link rel="stylesheet" href="test.css">
@@ -72,4 +93,17 @@ class ProcessorsTest < ActiveSupport::TestCase
72
93
  <p>test</p>
73
94
  }
74
95
  end
96
+
97
+ test "processing sass stylesheets should work" do
98
+ processor = StylesheetSassProcessorStub.new
99
+ processed = processor.process(@context, @body, @directory)
100
+
101
+ assert_equal processed, %q{
102
+ <link rel="import" href="test.html">
103
+ <style>p { color: red; }
104
+ </style>
105
+ <script src="test.js"></script>
106
+ <p>test</p>
107
+ }
108
+ end
75
109
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emcee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Huth
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-07 00:00:00.000000000 Z
11
+ date: 2014-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sass
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: sqlite3
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -49,21 +63,24 @@ files:
49
63
  - Rakefile
50
64
  - lib/emcee.rb
51
65
  - lib/emcee/compressors/html_compressor.rb
52
- - lib/emcee/helpers/action_view/asset_tag_helper.rb
53
- - lib/emcee/helpers/action_view/asset_url_helper.rb
54
- - lib/emcee/helpers/sprockets/compressing_helpers.rb
55
- - lib/emcee/helpers/sprockets/view_helpers.rb
56
- - lib/emcee/processors/html_processor.rb
57
- - lib/emcee/processors/processor_includes.rb
66
+ - lib/emcee/helpers/asset_tag_helper.rb
67
+ - lib/emcee/helpers/asset_url_helper.rb
68
+ - lib/emcee/helpers/sprockets_helper.rb
69
+ - lib/emcee/loose_assets.rb
70
+ - lib/emcee/processors/directive_processor.rb
71
+ - lib/emcee/processors/import_processor.rb
72
+ - lib/emcee/processors/script_processor.rb
73
+ - lib/emcee/processors/stylesheet_processor.rb
58
74
  - lib/emcee/railtie.rb
59
75
  - lib/emcee/version.rb
60
76
  - lib/generators/emcee/install/install_generator.rb
61
77
  - lib/generators/emcee/install/templates/application.html
62
78
  - test/compressors_test.rb
63
- - test/controllers_test.rb
64
79
  - test/dummy/README.rdoc
65
80
  - test/dummy/Rakefile
66
81
  - test/dummy/app/assets/elements/application.html
82
+ - test/dummy/app/assets/elements/compile/test5.css.scss
83
+ - test/dummy/app/assets/elements/compile/test5.html
67
84
  - test/dummy/app/assets/elements/test/test2.html
68
85
  - test/dummy/app/assets/elements/test/test3.css
69
86
  - test/dummy/app/assets/elements/test/test3.html
@@ -104,9 +121,11 @@ files:
104
121
  - test/dummy/public/500.html
105
122
  - test/dummy/public/favicon.ico
106
123
  - test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705
124
+ - test/dummy/tmp/cache/assets/test/sprockets/1b8013559a887e8b8d91472ef246fef9
107
125
  - test/dummy/tmp/cache/assets/test/sprockets/1e24025f59396708b3bb44543bed32fc
108
126
  - test/dummy/tmp/cache/assets/test/sprockets/219d0afb67879a67bae32b4fe4c708ac
109
127
  - test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af
128
+ - test/dummy/tmp/cache/assets/test/sprockets/2f90dac85033dad7b068860c3f6b7b27
110
129
  - test/dummy/tmp/cache/assets/test/sprockets/32cae461a9446107294c8a0230f5080c
111
130
  - test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953
112
131
  - test/dummy/tmp/cache/assets/test/sprockets/4fd1effec4d6579ba9d4f03ed156a15b
@@ -122,7 +141,7 @@ files:
122
141
  - test/dummy/tmp/cache/assets/test/sprockets/ffd4adb86602a60c7fcedd5d472166d3
123
142
  - test/dummy/vendor/assets/elements/test4.html
124
143
  - test/dummy/vendor/assets/elements/test4.js
125
- - test/emcee_test.rb
144
+ - test/dummy_app_integration_test.rb
126
145
  - test/helpers_test.rb
127
146
  - test/processors_test.rb
128
147
  - test/test_helper.rb
@@ -152,8 +171,9 @@ specification_version: 4
152
171
  summary: Add web components to the asset pipeline.
153
172
  test_files:
154
173
  - test/compressors_test.rb
155
- - test/controllers_test.rb
156
174
  - test/dummy/app/assets/elements/application.html
175
+ - test/dummy/app/assets/elements/compile/test5.css.scss
176
+ - test/dummy/app/assets/elements/compile/test5.html
157
177
  - test/dummy/app/assets/elements/test/test2.html
158
178
  - test/dummy/app/assets/elements/test/test3.css
159
179
  - test/dummy/app/assets/elements/test/test3.html
@@ -196,9 +216,11 @@ test_files:
196
216
  - test/dummy/Rakefile
197
217
  - test/dummy/README.rdoc
198
218
  - test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705
219
+ - test/dummy/tmp/cache/assets/test/sprockets/1b8013559a887e8b8d91472ef246fef9
199
220
  - test/dummy/tmp/cache/assets/test/sprockets/1e24025f59396708b3bb44543bed32fc
200
221
  - test/dummy/tmp/cache/assets/test/sprockets/219d0afb67879a67bae32b4fe4c708ac
201
222
  - test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af
223
+ - test/dummy/tmp/cache/assets/test/sprockets/2f90dac85033dad7b068860c3f6b7b27
202
224
  - test/dummy/tmp/cache/assets/test/sprockets/32cae461a9446107294c8a0230f5080c
203
225
  - test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953
204
226
  - test/dummy/tmp/cache/assets/test/sprockets/4fd1effec4d6579ba9d4f03ed156a15b
@@ -214,7 +236,7 @@ test_files:
214
236
  - test/dummy/tmp/cache/assets/test/sprockets/ffd4adb86602a60c7fcedd5d472166d3
215
237
  - test/dummy/vendor/assets/elements/test4.html
216
238
  - test/dummy/vendor/assets/elements/test4.js
217
- - test/emcee_test.rb
239
+ - test/dummy_app_integration_test.rb
218
240
  - test/helpers_test.rb
219
241
  - test/processors_test.rb
220
242
  - test/test_helper.rb
@@ -1,35 +0,0 @@
1
- module Sprockets
2
- module Compressing
3
- # Modify Sprocket's Compressing module to allow us to set and retrieve html
4
- # compressors
5
-
6
- def html_compressor
7
- @html_compressor if defined? @html_compressor
8
- end
9
-
10
- # Assign a compressor to run on 'text/html' assets.
11
- #
12
- # The compressor object must respond to 'compress'.
13
- def html_compressor=(compressor)
14
- unregister_bundle_processor 'text/html', html_compressor if html_compressor
15
- @html_compressor = nil
16
- return unless compressor
17
-
18
- if compressor.is_a?(Symbol)
19
- compressor = compressors['text/html'][compressor] || raise(Error, "unknown compressor: #{compressor}")
20
- end
21
-
22
- if compressor.respond_to?(:compress)
23
- klass = Class.new(::Sprockets::Processor) do
24
- @name = "html_compressor"
25
- @processor = proc { |context, data| compressor.compress(data) }
26
- end
27
- @html_compressor = :html_compressor
28
- else
29
- @html_compressor = klass = compressor
30
- end
31
-
32
- register_bundle_processor "text/html", klass
33
- end
34
- end
35
- end
@@ -1,84 +0,0 @@
1
- require "emcee/processors/processor_includes"
2
-
3
- module Emcee
4
- module Processors
5
- # HtmlProcessor processes html files by doing 4 things:
6
- #
7
- # 1. Stripping out asset pipeline directives and processing the associated
8
- # files.
9
- # 2. Stripping out html imports and processing those files.
10
- # 3. Stripping out external stylesheet includes, and inlining those sheets
11
- # where they were called.
12
- # 4. Stripping out external script tags, and inlining those scripts where
13
- # they were called.
14
- #
15
- # It inherits from Sprocket::DirectiveProcessor, which does most of the
16
- # work for us.
17
- #
18
- class HtmlProcessor < Sprockets::DirectiveProcessor
19
- # Include methods to process different parts of the html file. These are
20
- # split out to make unit testing easier.
21
- include Emcee::Processors::Includes
22
- protected :process_imports
23
- protected :process_stylesheets
24
- protected :process_scripts
25
- private :read_file
26
-
27
- # Matches the entire header/directive block. This is everything from the
28
- # top of the file, enclosed in html comments.
29
- #
30
- # ---
31
- #
32
- # \A matches the beginning of the string
33
- # (?m:\s*) matches whitespace, including \n
34
- # (<!--(?m:.*?)-->) matches html comments and their content
35
- #
36
- HEADER_PATTERN = /\A((?m:\s*)(<!--(?m:.*?)-->))+/
37
-
38
- # Matches the an asset pipeline directive.
39
- #
40
- # *= require_tree .
41
- #
42
- # ---
43
- #
44
- # ^ matches the beginning of the line
45
- # \W* matches any non-word character, zero or more times
46
- # = matches =, obviously
47
- # \s* matches any whitespace character, zero or more times
48
- # (\w+.*?) matches a group of characters, starting with a letter or number
49
- # $ matches the end of the line
50
- #
51
- DIRECTIVE_PATTERN = /^\W*=\s*(\w+.*?)$/
52
-
53
- # Render takes the actual text of the file and does our processing to it.
54
- # This is based on the standard render method on Sprockets's
55
- # DirectiveProcessor.
56
- #
57
- def render(context, locals)
58
- @context = context
59
- @pathname = context.pathname
60
- @directory = File.dirname(@pathname)
61
-
62
- @header = data[HEADER_PATTERN, 0] || ""
63
- @body = $' || data
64
- # Ensure body ends in a new line
65
- @body += "\n" if @body != "" && @body !~ /\n\Z/m
66
-
67
- @included_pathnames = []
68
-
69
- @result = ""
70
- @result.force_encoding(body.encoding)
71
-
72
- @has_written_body = false
73
-
74
- process_directives
75
- @body = process_imports(@body, @context, @directory)
76
- @body = process_stylesheets(@body, @directory)
77
- @body = process_scripts(@body, @directory)
78
- process_source
79
-
80
- @result
81
- end
82
- end
83
- end
84
- end
@@ -1,111 +0,0 @@
1
- module Emcee
2
- module Processors
3
- # This module defines methods that we will include into HtmlProcessor.
4
- #
5
- # Testing a class that inherits from Sprockets::DirectiveProcessor, which
6
- # HtmlProcessor does, is difficult. Seperating out these methods makes them
7
- # easy to unit test.
8
- #
9
- module Includes
10
- # Match an html import tag.
11
- #
12
- # <link rel="import" href="assets/example.html">
13
- #
14
- IMPORT_PATTERN = /^\s*<link .*rel=["']import["'].*>$/
15
-
16
- # Match a stylesheet link tag.
17
- #
18
- # <link rel="stylesheet" href="assets/example.css">
19
- #
20
- STYLESHEET_PATTERN = /^\s*<link .*rel=["']stylesheet["'].*>$/
21
-
22
- # Match a script tag.
23
- #
24
- # <script src="assets/example.js"></script>
25
- #
26
- SCRIPT_PATTERN = /^\s*<script .*src=["'].+\.js["']><\/script>$/
27
-
28
- # Match the path from the href attribute of an html import or stylesheet
29
- # include tag. Captures the actual path.
30
- #
31
- # href="/assets/example.css"
32
- #
33
- HREF_PATH_PATTERN = /href=["'](?<path>[\w\.\/-]+)["']/
34
-
35
- # Match the source path from a script tag. Captures the actual path.
36
- #
37
- # src="/assets/example.js"
38
- #
39
- SRC_PATH_PATTERN = /src=["'](?<path>[\w\.\/-]+)["']/
40
-
41
- # Match the indentation whitespace of a line
42
- #
43
- INDENT_PATTERN = /^(?<indent>\s*)/
44
-
45
- # Return a file's contents as text. This is split out as a method so that
46
- # we can test the other methods in this module without actually reading from
47
- # the filesystem.
48
- def read_file(path)
49
- File.read(path)
50
- end
51
-
52
- # Scan the body for html imports. If any are found, tell sprockets to
53
- # require their files like we would for a directive. Then remove the
54
- # imports and return the new body.
55
- def process_imports(body, context, directory)
56
- body.scan(IMPORT_PATTERN) do |import_tag|
57
- if path = import_tag[HREF_PATH_PATTERN, :path]
58
- absolute_path = File.absolute_path(path, directory)
59
- context.require_asset(absolute_path)
60
- end
61
- end
62
-
63
- body.gsub(IMPORT_PATTERN, "")
64
- end
65
-
66
- # Scan the body for external script references. If any are found, inline
67
- # the files in place of the references and return the new body.
68
- def process_scripts(body, directory)
69
- to_inline = []
70
-
71
- body.scan(SCRIPT_PATTERN) do |script_tag|
72
- if path = script_tag[SRC_PATH_PATTERN, :path]
73
-
74
- indent = script_tag[INDENT_PATTERN, :indent] || ""
75
-
76
- absolute_path = File.absolute_path(path, directory)
77
- script_contents = read_file(absolute_path)
78
-
79
- to_inline << [script_tag, "#{indent}<script>#{script_contents}\n#{indent}</script>"]
80
- end
81
- end
82
-
83
- to_inline.reduce(body) do |output, (tag, contents)|
84
- output.gsub(tag, contents)
85
- end
86
- end
87
-
88
- # Scan the body for external stylesheet references. If any are found,
89
- # inline the files in place of the references and return the new body.
90
- def process_stylesheets(body, directory)
91
- to_inline = []
92
-
93
- body.scan(STYLESHEET_PATTERN) do |stylesheet_tag|
94
- if path = stylesheet_tag[HREF_PATH_PATTERN, :path]
95
-
96
- indent = stylesheet_tag[INDENT_PATTERN, :indent] || ""
97
-
98
- absolute_path = File.absolute_path(path, directory)
99
- stylesheet_contents = read_file(absolute_path)
100
-
101
- to_inline << [stylesheet_tag, "#{indent}<style>#{stylesheet_contents}\n#{indent}</style>"]
102
- end
103
- end
104
-
105
- to_inline.reduce(body) do |output, (tag, contents)|
106
- output.gsub(tag, contents)
107
- end
108
- end
109
- end
110
- end
111
- end