Class: Markdownator::Engine

Inherits:
Object
  • Object
show all
Defined in:
lib/markdownator/engine.rb,
sig/markdownator.rbs

Overview

Orchestrator that holds an ordered list of converters and dispatches an input (local path, URL, or IO stream) to the first converter that accepts it.

Constant Summary collapse

DEFAULT_CONVERTER_ORDER =

Default converters, in priority order. More specific formats (the ZIP-based Office/EPUB containers) must come before the generic ZIP converter, and the plain-text fallback comes last.

%i[
  docx xlsx pptx epub zip pdf image html csv json xml plain_text
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(converters: nil, **options) ⇒ Engine



23
24
25
26
# File 'lib/markdownator/engine.rb', line 23

def initialize(converters: nil, **options)
  @converters = converters || self.class.default_converters
  @default_options = options
end

Instance Attribute Details

#convertersArray[untyped] (readonly)

Returns the value of attribute converters.



18
19
20
# File 'lib/markdownator/engine.rb', line 18

def converters
  @converters
end

Class Method Details

.camelize(name) ⇒ Object



34
35
36
# File 'lib/markdownator/engine.rb', line 34

def self.camelize(name)
  name.to_s.split("_").map(&:capitalize).join
end

.default_convertersObject



28
29
30
31
32
# File 'lib/markdownator/engine.rb', line 28

def self.default_converters
  DEFAULT_CONVERTER_ORDER.map do |name|
    Converters.const_get(camelize(name)).new
  end
end

Instance Method Details

#convert(source, **options) ⇒ Result

Permissive entry point: dispatches based on what source looks like.



39
40
41
42
43
44
45
46
47
# File 'lib/markdownator/engine.rb', line 39

def convert(source, **options)
  if source.respond_to?(:read)
    convert_stream(source, options.delete(:stream_info), **options)
  elsif url?(source)
    convert_url(source, **options)
  else
    convert_local(source, **options)
  end
end

#convert_local(path, **options) ⇒ Result

Converts a local file path.



50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/markdownator/engine.rb', line 50

def convert_local(path, **options)
  raise FileConversionError, "No such file: #{path}" unless File.file?(path)

  stream_info = StreamInfo.new(
    extension: File.extname(path),
    filename: File.basename(path),
    local_path: path
  )
  File.open(path, "rb") do |io|
    convert_stream(io, stream_info, **options)
  end
end

#convert_stream(io, stream_info = nil, **options) ⇒ Result

Converts an open IO stream. stream_info provides format hints.



80
81
82
83
84
85
86
87
88
89
90
# File 'lib/markdownator/engine.rb', line 80

def convert_stream(io, stream_info = nil, **options)
  stream_info ||= StreamInfo.new
  opts = @default_options.merge(options)
  opts[:engine] = self

  converter = pick_converter(io, stream_info)
  raise UnsupportedFormatError, describe_unsupported(stream_info) if converter.nil?

  io.rewind if io.respond_to?(:rewind)
  converter.convert(io, stream_info, **opts)
end

#convert_url(url, **options) ⇒ Result

Fetches an http(s) URL and converts the response body.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/markdownator/engine.rb', line 64

def convert_url(url, **options)
  uri = URI.parse(url)
  response = Net::HTTP.get_response(uri)
  raise FileConversionError, "HTTP #{response.code} fetching #{url}" unless response.is_a?(Net::HTTPSuccess)

  stream_info = StreamInfo.new(
    mimetype: response.content_type,
    extension: File.extname(uri.path.to_s),
    charset: response.type_params["charset"],
    filename: File.basename(uri.path.to_s),
    url: url
  )
  convert_stream(StringIO.new(response.body), stream_info, **options)
end