marcel_cr

Version, currently 2.1.01 version
  • 2.1.0latestOct 16, 2026

github.com/OrelSokolov/marcel.cr

Порт гема marcel 2.1.0 (github.com/rails/marcel) на Crystal — 1:1 API. Определение MIME-типа по magic-байтам, имени/расширению файла и объявленному типу: Marcel::MimeType.for, Marcel::Magic (add/remove/ canonicalize), уточнение XML по корневому элементу и ZIP/OOXML по central directory. Таблицы сгенерированы из оригинального lib/marcel/tables.rb (Tika + custom.xml).

0 stars
1 dependent
License: not declared

Installation

# Add this to your shard.yml
dependencies:
  marcel_cr:
    github: OrelSokolov/marcel.cr
    version: ~> 2.1.0

Then run:

shards install

shard.yml

Crystal
>= 1.21.0
Author
oleg

Dependencies

This version declares no dependencies.

README

marcel.cr

A Crystal port of the marcel 2.1.0 Ruby gem with a 1:1 API.

MIME type detection by magic bytes, file name/extension, and declared type: XML refinement by root element and ZIP/OOXML refinement by central directory. The tables are generated from the original lib/marcel/tables.rb (Tika + custom.xml), so results are identical to the Ruby gem.

Installation

  1. Add the shard to your shard.yml:
dependencies:
  marcel:
    github: OrelSokolov/marcel.cr
  1. Run shards install.

Usage

require "marcel"

Marcel::MimeType.for(Path["file.gif"])                       # => "image/gif"
Marcel::MimeType.for(IO::Memory.new(File.read("file.docx"))) # => "application/vnd..."
Marcel::MimeType.for(name: "file.xml")                       # => "application/xml"
Marcel::MimeType.for(extension: "pdf")                       # => "application/pdf"
Marcel::MimeType.for(Path["book.mov"], name: "book.m4v",
                     declared_type: "video/mp4")             # priority: magic → name → type

MimeType.for accepts a Path (a file), an IO (content), a String (content) or nil, plus optional hints: name, extension, declared_type. A later candidate is used only if it is more specific than the type already found. If no type can be determined, application/octet-stream is returned.

Low-level API:

Marcel::Magic.by_path("image.png")    # => Marcel::Magic?
Marcel::Magic.by_extension("png")     # => Marcel::Magic?
Marcel::Magic.by_type("image/png")    # => Marcel::Magic?
Marcel::Magic.by_magic(io)            # slow: content analysis
Marcel::Magic.all_by_magic(io)        # all matching types

magic = Marcel::Magic.new("text/html")
magic.text?   # => true
magic.image?  # => false
magic.extensions
magic.child_of?("text/plain")

# Extending the registry (mutations are global, as in the Ruby gem):
Marcel::Magic.add("application/x-my-thing", extensions: "mtg",
                  parents: "application/json")
Marcel::Magic.remove("application/x-my-thing")
Marcel::Magic.canonicalize("application/x-my-thing", "text/x-my-thing")
Marcel::MimeType.extend("application/x-my-thing", extensions: %w(mtg))

Differences from the Ruby version

  • Path instead of Pathname; a String argument is treated as content, not a path.
  • Magic rule regexes run on PCRE2 (always in UTF mode) instead of Onigmo with the /n flag; the byte semantics are reproduced (see src/marcel/magic/xml.cr).
  • Non-UTF-8 XML document encodings are transcoded via iconv.

Development

crystal spec                # port of the gem's test suite (639 examples)
                            # + oracle cross-check (525 examples)

The cross-check compares the port against reference answers from the Ruby gem (spec/oracle_expected.yml). Regenerating the reference requires a system Ruby:

ruby script/generate_oracle_expected.rb

script/generate_tables.rb regenerates src/marcel/tables.cr from the oracle gem (usually not needed — the tables are already generated).

License

Same as the original gem — MIT and Apache-2.0. This port includes code from marcel (Copyright © Tom Ward and contributors) and mimemagic (Copyright © 2011 Daniel Mendler, MIT).