Class: Markdownator::Engine

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

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

Returns a new instance of Engine.

Parameters:

  • converters (Array<Converters::Base>) (defaults to: nil)

    custom converter chain.

  • options (Hash)

    default options threaded into every conversion (e.g. ‘captioner:`).



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

#convertersObject (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) ⇒ Object

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) ⇒ Object

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) ⇒ Object

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) ⇒ Object

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