asciidoctor-diagram 2.0.5 → 2.1.0

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +17 -2
  3. data/README.adoc +25 -516
  4. data/Rakefile +1 -1
  5. data/docs/antora.yml +3 -0
  6. data/{images → docs/modules/ROOT/images}/asciidoctor-diagram-classes.png +0 -0
  7. data/docs/modules/ROOT/images/asciidoctor-diagram-process.png +0 -0
  8. data/docs/modules/ROOT/pages/index.adoc +21 -0
  9. data/docs/modules/ROOT/partials/advanced.adoc +303 -0
  10. data/docs/modules/ROOT/partials/create_diagram.adoc +131 -0
  11. data/docs/modules/ROOT/partials/generate.adoc +15 -0
  12. data/docs/modules/ROOT/partials/installation.adoc +19 -0
  13. data/docs/modules/ROOT/partials/uris.adoc +38 -0
  14. data/examples/features.adoc +1 -1
  15. data/lib/asciidoctor-diagram/diagram_processor.rb +2 -1
  16. data/lib/asciidoctor-diagram/ditaa/converter.rb +14 -5
  17. data/lib/asciidoctor-diagram/ditaa/ditaa-1.3.17.jar +0 -0
  18. data/lib/asciidoctor-diagram/http/converter.rb +1 -7
  19. data/lib/asciidoctor-diagram/lilypond/converter.rb +11 -1
  20. data/lib/asciidoctor-diagram/meme/converter.rb +15 -9
  21. data/lib/asciidoctor-diagram/mermaid/converter.rb +27 -10
  22. data/lib/asciidoctor-diagram/pikchr/converter.rb +8 -1
  23. data/lib/asciidoctor-diagram/plantuml/converter.rb +15 -9
  24. data/lib/asciidoctor-diagram/plantuml/plantuml-1.3.17.jar +0 -0
  25. data/lib/asciidoctor-diagram/svgbob/converter.rb +4 -0
  26. data/lib/asciidoctor-diagram/util/cli.rb +16 -1
  27. data/lib/asciidoctor-diagram/util/cli_generator.rb +4 -2
  28. data/lib/asciidoctor-diagram/util/gif.rb +1 -1
  29. data/lib/asciidoctor-diagram/util/java.rb +5 -3
  30. data/lib/asciidoctor-diagram/util/java_jruby.rb +4 -1
  31. data/lib/asciidoctor-diagram/util/java_socket.rb +10 -1
  32. data/lib/asciidoctor-diagram/util/pdf.rb +1 -1
  33. data/lib/asciidoctor-diagram/util/png.rb +1 -1
  34. data/lib/asciidoctor-diagram/util/server-1.3.17.jar +0 -0
  35. data/lib/asciidoctor-diagram/util/svg.rb +25 -4
  36. data/lib/asciidoctor-diagram/version.rb +1 -1
  37. data/spec/a2s_spec.rb +3 -3
  38. data/spec/blockdiag_spec.rb +3 -3
  39. data/spec/bytefield_spec.rb +3 -3
  40. data/spec/ditaa_spec.rb +1 -1
  41. data/spec/dpic_spec.rb +3 -3
  42. data/spec/erd_spec.rb +5 -5
  43. data/spec/lilypond_spec.rb +3 -3
  44. data/spec/mermaid_spec.rb +37 -0
  45. data/spec/pikchr_spec.rb +21 -3
  46. data/spec/shaape_spec.rb +3 -3
  47. data/spec/svgbob_spec.rb +3 -3
  48. data/spec/syntrax_spec.rb +3 -3
  49. data/spec/test_helper.rb +3 -7
  50. data/spec/tikz_spec.rb +3 -3
  51. metadata +57 -13
  52. data/README_zh-CN.adoc +0 -336
  53. data/images/asciidoctor-diagram-process.png +0 -0
  54. data/lib/batik-all-1.10.jar +0 -0
  55. data/lib/ditaa-1.3.15.jar +0 -0
  56. data/lib/ditaamini-0.12.jar +0 -0
  57. data/lib/jlatexmath-minimal-1.0.5.jar +0 -0
  58. data/lib/plantuml-1.3.15.jar +0 -0
  59. data/lib/plantuml.jar +0 -0
  60. data/lib/server-1.3.15.jar +0 -0
@@ -0,0 +1,15 @@
1
+ == Generating a Diagram from a Terminal
2
+
3
+ You can load Asciidoctor diagram in a terminal using the `-r` flag.
4
+
5
+ $ asciidoctor -r asciidoctor-diagram sample.adoc
6
+
7
+ You can also use Asciidoctor diagram with other converters, such as Asciidoctor EPUB.
8
+ Asciidoctor-epub3 is also loaded with the `-r` flag.
9
+
10
+ $ asciidoctor -r asciidoctor-diagram -r asciidoctor-epub3 -b epub3 sample.adoc
11
+
12
+ Or, you can invoke Asciidoctor and the EPUB converter with the `asciidoctor-epub3` command.
13
+ The command implicitly sets the `-r` and `-b` flags for EPUB3 output.
14
+
15
+ $ asciidoctor-epub3 -r asciidoctor-diagram sample.adoc
@@ -0,0 +1,19 @@
1
+ == Installation
2
+
3
+ Asciidoctor Diagram is a RubyGem, which can be installed using the `gem` or `bundle` commands.
4
+
5
+ You can install the Asciidoctor Diagram gem by typing `gem install` in the CLI.
6
+
7
+ $ gem install asciidoctor-diagram
8
+
9
+ by first adding the following entry to your project's [.path]_Gemfile_.
10
+
11
+ .Gemfile
12
+ [source,ruby]
13
+ ----
14
+ gem 'asciidoctor-diagram'
15
+ ----
16
+
17
+ Then execute `bundle` in the CLI.
18
+
19
+ $ bundle
@@ -0,0 +1,38 @@
1
+ :uri-a2s: https://github.com/dhobsd/asciitosvg
2
+ :uri-actdiag: http://blockdiag.com/en/actdiag/index.html
3
+ :uri-asciidoctor-api: http://asciidoctor.org/docs/user-manual/#api
4
+ :uri-asciidoctor-extensions: http://asciidoctor.org/docs/user-manual/#extension-points
5
+ :uri-blockdiag: http://blockdiag.com
6
+ :uri-bpmn: https://github.com/gtudan/bpmn-js-cmd
7
+ :uri-bytefield: https://github.com/Deep-Symmetry/bytefield-svg
8
+ :uri-ditaa: http://ditaa.sourceforge.net/
9
+ :uri-dpic: https://gitlab.com/aplevich/dpic
10
+ :uri-dot: https://graphviz.gitlab.io/_pages/doc/info/lang.html
11
+ :uri-erd: https://github.com/BurntSushi/erd
12
+ :uri-gnuplot: http://gnuplot.info
13
+ :uri-graphviz: https://graphviz.gitlab.io
14
+ :uri-imagemagick: http://www.imagemagick.org
15
+ :uri-java: http://java.sun.com
16
+ :uri-mermaid: https://github.com/mermaid-js/mermaid-cli
17
+ :uri-mscgen: http://www.mcternan.me.uk/mscgen/
18
+ :uri-nomnoml: http://nomnoml.com
19
+ :uri-nwdiag: http://blockdiag.com/en/nwdiag/index.html
20
+ :uri-packetdiag: http://blockdiag.com/en/nwdiag/index.html
21
+ :uri-phantomjs: http://phantomjs.org
22
+ :uri-pikchr: https://pikchr.org
23
+ :uri-plantuml: http://plantuml.sourceforge.net
24
+ :uri-py-plantuml: https://code.google.com/p/asciidoc-plantuml/
25
+ :uri-rackdiag: http://blockdiag.com/en/nwdiag/index.html
26
+ :uri-seqdiag: http://blockdiag.com/en/seqdiag/index.html
27
+ :uri-shaape: https://github.com/christiangoltz/shaape
28
+ :uri-smcat: https://github.com/sverweij/state-machine-cat
29
+ :uri-svgbob: https://github.com/ivanceras/svgbobrus
30
+ :uri-symbolator: https://github.com/kevinpt/symbolator
31
+ :uri-syntrax: https://kevinpt.github.io/syntrax/
32
+ :uri-tikz: https://github.com/pgf-tikz/pgf
33
+ :uri-umlet: http://www.umlet.com/
34
+ :uri-vega: https://vega.github.io/vega/
35
+ :uri-vegalite: https://vega.github.io/vega-lite/
36
+ :uri-wavedrom: http://wavedrom.com
37
+ :uri-wavedromeditor: https://github.com/wavedrom/wavedrom.github.io/releases
38
+ :uri-wavedromcli: https://github.com/wavedrom/cli
@@ -150,7 +150,7 @@ results in a block with the correct caption and id applied to it.
150
150
  Asciidoctor-diagram also supports the various diagram block in block macro form.
151
151
  These are macros of the form `<name>::<target>[<attrlist>]`.
152
152
 
153
- In asciidoctor-diagram the macro names are identical to the block styles: `ditaa`, `graphivz` and `plantuml`
153
+ In asciidoctor-diagram the macro names are identical to the block styles: `ditaa`, `graphviz` and `plantuml`
154
154
  The target is the path to the file containing the diagram source code.
155
155
  When the target is a relative path it is resolved with respect to the location of the document being processed.
156
156
  The attribute list behaves mostly the same as with the block styles.
@@ -174,7 +174,8 @@ module Asciidoctor
174
174
  metadata = source.create_image_metadata
175
175
  metadata[:options] = options
176
176
 
177
- result, metadata[:width], metadata[:height] = params[:decoder].post_process_image(result)
177
+ allow_image_optimisation = source.attr('optimise', 'true') == 'true'
178
+ result, metadata[:width], metadata[:height] = params[:decoder].post_process_image(result, allow_image_optimisation)
178
179
 
179
180
  FileUtils.mkdir_p(File.dirname(image_file)) unless Dir.exist?(File.dirname(image_file))
180
181
  File.open(image_file, 'wb') {|f| f.write result}
@@ -23,11 +23,20 @@ module Asciidoctor
23
23
  :transparent => lambda { |o, v| o << '--transparent' if v == 'true'}
24
24
  }
25
25
 
26
- JARS = ['ditaa-1.3.15.jar', 'ditaamini-0.12.jar'].map do |jar|
27
- File.expand_path File.join('../..', jar), File.dirname(__FILE__)
28
- end
29
- Java.classpath.concat JARS
30
-
26
+ CLASSPATH_ENV = 'DIAGRAM_DITAA_CLASSPATH'
27
+ DITAA_JARS = if ENV.has_key?(CLASSPATH_ENV)
28
+ ENV[CLASSPATH_ENV].split(File::PATH_SEPARATOR)
29
+ else
30
+ begin
31
+ require 'asciidoctor-diagram/ditaa/classpath'
32
+ ::Asciidoctor::Diagram::DitaaClasspath::JAR_FILES
33
+ rescue LoadError
34
+ raise "Could not load PlantUML. Eiter require 'asciidoctor-diagram-ditaamini' or specify the location of the PlantUML JAR(s) using the 'DIAGRAM_DITAA_CLASSPATH' environment variable."
35
+ end
36
+ end
37
+
38
+ Java.classpath.concat Dir[File.join(File.dirname(__FILE__), '*.jar')]
39
+ Java.classpath.concat DITAA_JARS
31
40
 
32
41
  def supported_formats
33
42
  [:png, :svg]
@@ -23,12 +23,6 @@ module Asciidoctor
23
23
  @converter.supported_formats
24
24
  end
25
25
 
26
- def collect_options(source, name)
27
- {
28
- :block_name => name
29
- }
30
- end
31
-
32
26
  def convert(source, format, options)
33
27
  code = source.code
34
28
 
@@ -58,7 +52,7 @@ module Asciidoctor
58
52
 
59
53
  path = uri.path
60
54
  path << '/' unless path.end_with? '/'
61
- path << options[:block_name].to_s
55
+ path << source.diagram_type.to_s
62
56
  path << '/' << format.to_s
63
57
  path << '/' << data
64
58
  uri.path = path
@@ -9,6 +9,16 @@ module Asciidoctor
9
9
  include DiagramConverter
10
10
  include CliGenerator
11
11
 
12
+ EXTRA_PATH = []
13
+
14
+ if ::Asciidoctor::Diagram::Platform.os == :macosx
15
+ lilypond_app = ::Asciidoctor::Diagram::Which.which('LilyPond.app', :path => ['/Applications'])
16
+ if lilypond_app
17
+ EXTRA_PATH << File.join(lilypond_app, 'Contents/Resources/bin')
18
+ end
19
+ end
20
+
21
+ EXTRA_PATH.freeze
12
22
 
13
23
  def supported_formats
14
24
  [:png, :pdf]
@@ -34,7 +44,7 @@ module Asciidoctor
34
44
 
35
45
  resolution = options[:resolution]
36
46
 
37
- generate_stdin(source.find_command('lilypond'), format.to_s, code) do |tool_path, output_path|
47
+ generate_stdin(source.find_command('lilypond', :path => EXTRA_PATH), format.to_s, code) do |tool_path, output_path|
38
48
  args = [tool_path, '-daux-files=#f', '-dbackend=eps', '-dno-gs-load-fonts', '-dinclude-eps-fonts', '-o', Platform.native_path(output_path), '-f', format.to_s]
39
49
 
40
50
  args << '-dsafe'
@@ -34,8 +34,16 @@ module Asciidoctor
34
34
  end
35
35
 
36
36
  def convert(source, format, options)
37
- convert = source.find_command('convert')
38
- identify = source.find_command('identify')
37
+ magick = source.find_command('magick', :raise_on_error => false)
38
+ if magick
39
+ convert = ->(*args) { Cli.run(magick, 'convert', *args) }
40
+ identify = ->(*args) { Cli.run(magick, 'identify', *args) }
41
+ else
42
+ convert_cmd = source.find_command('convert')
43
+ convert = ->(*args) { Cli.run(convert_cmd, *args) }
44
+ identify_cmd = source.find_command('identify')
45
+ identify = ->(*args) { Cli.run(identify_cmd, *args) }
46
+ end
39
47
 
40
48
  bg_img = options[:bg_img]
41
49
  raise "background attribute is required" unless bg_img
@@ -50,7 +58,7 @@ module Asciidoctor
50
58
  font = options[:font] || 'Impact'
51
59
  noupcase = options[:noupcase]
52
60
 
53
- dimensions = Cli.run(identify, '-format', '%w %h', bg_img)[:out].match(/(?<w>\d+) (?<h>\d+)/)
61
+ dimensions = identify.call('-format', '%w %h', bg_img)[:out].match(/(?<w>\d+) (?<h>\d+)/)
54
62
  bg_width = dimensions['w'].to_i
55
63
  bg_height = dimensions['h'].to_i
56
64
  label_width = bg_width
@@ -58,8 +66,7 @@ module Asciidoctor
58
66
 
59
67
  if top_label
60
68
  top_img = Tempfile.new(['meme', '.png'])
61
- Cli.run(
62
- convert,
69
+ convert.call(
63
70
  '-background', 'none',
64
71
  '-fill', fill_color,
65
72
  '-stroke', stroke_color,
@@ -76,8 +83,7 @@ module Asciidoctor
76
83
 
77
84
  if bottom_label
78
85
  bottom_img = Tempfile.new(['meme', '.png'])
79
- Cli.run(
80
- convert,
86
+ convert.call(
81
87
  '-background', 'none',
82
88
  '-fill', fill_color,
83
89
  '-stroke', stroke_color,
@@ -94,7 +100,7 @@ module Asciidoctor
94
100
 
95
101
  final_img = Tempfile.new(['meme', ".#{format.to_s}"])
96
102
 
97
- args = [convert, bg_img]
103
+ args = [bg_img]
98
104
  if top_img
99
105
  args << top_img.path << '-geometry' << '+0+0' << '-composite'
100
106
  end
@@ -105,7 +111,7 @@ module Asciidoctor
105
111
 
106
112
  args << final_img.path
107
113
 
108
- Cli.run(*args)
114
+ convert.call(*args)
109
115
 
110
116
  File.binread(final_img)
111
117
  end
@@ -64,9 +64,15 @@ module Asciidoctor
64
64
 
65
65
  opts[:width] = options[:width]
66
66
 
67
- mmdc = source.find_command('mmdc', :raise_on_error => false)
68
- node = source.find_command('node', :raise_on_error => false)
69
- if mmdc && node
67
+ mmdc = nil
68
+ mmdc_exception = nil
69
+ begin
70
+ mmdc = source.find_command('mmdc')
71
+ rescue => e
72
+ mmdc_exception = e
73
+ end
74
+
75
+ if mmdc
70
76
  opts[:height] = options[:height]
71
77
  opts[:scale] = options[:scale]
72
78
  opts[:theme] = options[:theme]
@@ -75,17 +81,25 @@ module Asciidoctor
75
81
  if config
76
82
  opts[:config] = source.resolve_path(config)
77
83
  end
78
- run_mmdc(node, mmdc, source, format, opts)
84
+ run_mmdc(mmdc, source, format, opts)
79
85
  else
80
- mermaid = source.find_command('mermaid')
81
- run_mermaid(mermaid, source, format, opts)
86
+ begin
87
+ mermaid = source.find_command('mermaid')
88
+ run_mermaid(mermaid, source, format, opts)
89
+ rescue
90
+ if mmdc_exception
91
+ raise mmdc_exception
92
+ else
93
+ raise
94
+ end
95
+ end
82
96
  end
83
97
  end
84
98
 
85
99
  private
86
- def run_mmdc(node, mmdc, source, format, options = {})
87
- generate_file(node, 'mmd', format.to_s, source.to_s) do |tool_path, input_path, output_path|
88
- args = [tool_path, '--unhandled-rejections=strict', mmdc, '-i', Platform.native_path(input_path), '-o', Platform.native_path(output_path)]
100
+ def run_mmdc(mmdc, source, format, options = {})
101
+ generate_file(mmdc, 'mmd', format.to_s, source.to_s) do |tool_path, input_path, output_path|
102
+ args = [tool_path, '-i', Platform.native_path(input_path), '-o', Platform.native_path(output_path)]
89
103
 
90
104
  if options[:css]
91
105
  args << '--cssFile' << Platform.native_path(options[:css])
@@ -148,7 +162,10 @@ module Asciidoctor
148
162
  args << '--puppeteerConfigFile' << Platform.native_path(options[:puppeteer])
149
163
  end
150
164
 
151
- args
165
+ {
166
+ :args => args,
167
+ :env => {'NODE_OPTIONS' => '--unhandled-rejections=strict'}
168
+ }
152
169
  end
153
170
  end
154
171
 
@@ -17,9 +17,16 @@ module Asciidoctor
17
17
  def convert(source, format, options)
18
18
  pikchr_path = source.find_command('pikchr')
19
19
 
20
- generate_file_stdout(pikchr_path, format.to_s, source.to_s) do |tool_path, input_path|
20
+ output = generate_file_stdout(pikchr_path, format.to_s, source.to_s) do |tool_path, input_path|
21
21
  [tool_path, "--svg-only", input_path]
22
22
  end
23
+
24
+ if output.start_with? '<svg'
25
+ output
26
+ else
27
+ error = output.gsub(/<\/?[a-z]+>\n?/i, '')
28
+ raise error
29
+ end
23
30
  end
24
31
  end
25
32
  end
@@ -7,15 +7,21 @@ module Asciidoctor
7
7
  class PlantUmlConverter
8
8
  include DiagramConverter
9
9
 
10
- JARS = [
11
- 'plantuml-1.3.15.jar',
12
- 'plantuml.jar',
13
- 'jlatexmath-minimal-1.0.5.jar',
14
- 'batik-all-1.10.jar'
15
- ].map do |jar|
16
- File.expand_path File.join('../..', jar), File.dirname(__FILE__)
17
- end
18
- Java.classpath.concat JARS
10
+ CLASSPATH_ENV = 'DIAGRAM_PLANTUML_CLASSPATH'
11
+ LIB_DIR = File.expand_path('../..', File.dirname(__FILE__))
12
+ PLANTUML_JARS = if ENV.has_key?(CLASSPATH_ENV)
13
+ ENV[CLASSPATH_ENV].split(File::PATH_SEPARATOR)
14
+ else
15
+ begin
16
+ require 'asciidoctor-diagram/plantuml/classpath'
17
+ ::Asciidoctor::Diagram::PlantUmlClasspath::JAR_FILES
18
+ rescue LoadError
19
+ raise "Could not load PlantUML. Eiter require 'asciidoctor-diagram-plantuml' or specify the location of the PlantUML JAR(s) using the 'DIAGRAM_PLANTUML_CLASSPATH' environment variable."
20
+ end
21
+ end
22
+
23
+ Java.classpath.concat Dir[File.join(File.dirname(__FILE__), '*.jar')].freeze
24
+ Java.classpath.concat PLANTUML_JARS
19
25
 
20
26
  def supported_formats
21
27
  [:png, :svg, :txt, :atxt, :utxt]
@@ -14,6 +14,10 @@ module Asciidoctor
14
14
  [:svg]
15
15
  end
16
16
 
17
+ def native_scaling?
18
+ true
19
+ end
20
+
17
21
  OPTIONS = {
18
22
  :font_family => lambda { |o, v| o << '--font-family' << v if v },
19
23
  :font_size => lambda { |o, v| o << '--font-size' << v if v },
@@ -12,7 +12,16 @@ module Asciidoctor
12
12
  opts = args.pop.dup if args.last.is_a? Hash
13
13
  in_data = opts && opts[:stdin_data]
14
14
 
15
+ if Hash === args.first
16
+ env = args.shift.dup
17
+ else
18
+ env = {}
19
+ end
20
+
15
21
  pb = java.lang.ProcessBuilder.new(*args)
22
+ env.each_pair do |key, value|
23
+ pb.environment.put(key, value)
24
+ end
16
25
  p = pb.start
17
26
 
18
27
  stdout = ""
@@ -67,12 +76,18 @@ module Asciidoctor
67
76
  opts = {}
68
77
  end
69
78
 
79
+ if Hash === args.first
80
+ env = args.shift.dup
81
+ else
82
+ env = {}
83
+ end
84
+
70
85
  # When the first argument is an array, we force capture3 (or better the underlying Kernel#spawn)
71
86
  # to use a non-shell execution variant.
72
87
  cmd = File.basename(args[0])
73
88
  args[0] = [args[0], cmd]
74
89
 
75
- stdout, stderr, status = Open3.capture3(*args, opts)
90
+ stdout, stderr, status = Open3.capture3(env, *args, opts)
76
91
 
77
92
  exit = status.exitstatus
78
93
 
@@ -74,15 +74,17 @@ module Asciidoctor
74
74
  when Array
75
75
  args = opts
76
76
  out_file = nil
77
+ env = {}
77
78
  when Hash
78
79
  args = opts[:args]
79
80
  out_file = opts[:out_file]
81
+ env = opts[:env] || {}
80
82
  else
81
83
  raise "Block passed to generate_file should return an Array or a Hash"
82
84
  end
83
85
 
84
- logger.debug "Executing #{args} with options #{open3_opts}"
85
- result = ::Asciidoctor::Diagram::Cli.run(*args, open3_opts)
86
+ logger.debug "Executing #{args} with options #{open3_opts} and environment #{env}"
87
+ result = ::Asciidoctor::Diagram::Cli.run(env, *args, open3_opts)
86
88
 
87
89
  data = target_file == :stdout ? result[:out] : read_result(target_file, out_file)
88
90
 
@@ -7,7 +7,7 @@ module Asciidoctor
7
7
  GIF87A_SIGNATURE = 'GIF87a'.force_encoding(Encoding::ASCII_8BIT)
8
8
  GIF89A_SIGNATURE = 'GIF89a'.force_encoding(Encoding::ASCII_8BIT)
9
9
 
10
- def self.post_process_image(data)
10
+ def self.post_process_image(data, optimise)
11
11
  bio = BinaryIO.new(data)
12
12
  gif_signature = bio.read_string(6)
13
13
  raise "Invalid GIF signature" unless gif_signature == GIF87A_SIGNATURE || gif_signature == GIF89A_SIGNATURE
@@ -5,9 +5,7 @@ module Asciidoctor
5
5
  # @private
6
6
  module Java
7
7
  def self.classpath
8
- @classpath ||= [
9
- File.expand_path(File.join('../..', 'server-1.3.15.jar'), File.dirname(__FILE__))
10
- ]
8
+ @classpath ||= Dir[File.join(File.dirname(__FILE__), '*.jar')]
11
9
  end
12
10
 
13
11
  CRLF = "\r\n".encode(Encoding::US_ASCII)
@@ -53,6 +51,10 @@ module Asciidoctor
53
51
  io.set_encoding Encoding::US_ASCII
54
52
  status_line = io.readline(CRLF)
55
53
  status_line_parts = STATUS_LINE.match status_line
54
+ unless status_line_parts
55
+ raise "Unexpected HTTP status line: #{status_line}"
56
+ end
57
+
56
58
  resp[:code] = status_line_parts[1].to_i
57
59
  resp[:reason] = status_line_parts[2]
58
60