Project

comicinfo

0.0
No release in over 3 years
An idiomatic Ruby interface for reading and writing ComicInfo.xml files, following the official ComicInfo schema specifications from the Anansi Project
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

>= 1.18.10
 Project Readme

ComicInfo Ruby Gem

A Ruby gem that provides an idiomatic interface for reading and writing ComicInfo.xml files, following the official ComicInfo schema specifications from the Anansi Project.

Ruby Gem Version License: MIT

Features

  • ๐Ÿ“š Complete Schema Support: Full ComicInfo v2.0 schema implementation
  • ๐Ÿ”ง Idiomatic Ruby API: Ruby-style interface with proper method naming
  • ๐Ÿ“ Flexible Loading: Load from file paths or XML strings
  • ๐ŸŒ Unicode Support: Full Unicode and special character handling
  • ๐Ÿ“– Manga Support: Right-to-left reading direction and manga-specific fields
  • โœ… Comprehensive Validation: Schema-compliant enum validation and type coercion
  • ๐Ÿšจ Detailed Error Handling: Custom exception classes with helpful error messages
  • ๐Ÿ“Š Export Support: JSON, YAML, and XML serialization with hash representation
  • โœ๏ธ XML Generation: Complete ComicInfo.xml writing with round-trip consistency

Installation

Add this line to your application's Gemfile:

gem 'comicinfo'

And then execute:

bundle install

Or install it yourself as:

gem install comicinfo

Usage

Loading ComicInfo Files

require 'comicinfo'

# Load from file path
comic = ComicInfo.load 'path/to/ComicInfo.xml'

# Load from XML string
xml_content = File.read 'ComicInfo.xml'
comic       = ComicInfo.load xml_content

Accessing Comic Information

# Basic information
puts comic.title  #=> "The Amazing Spider-Man"
puts comic.series #=> "The Amazing Spider-Man"
puts comic.number #=> "1"
puts comic.count  #=> 600
puts comic.volume #=> 3

# Publication details
puts comic.publisher #=> "Marvel Comics"
puts comic.year      #=> 2018
puts comic.month     #=> 3
puts comic.day       #=> 15

# Creator information
puts comic.writer       #=> "Dan Slott, Christos Gage"
puts comic.penciller    #=> "Ryan Ottley"
puts comic.cover_artist #=> "Ryan Ottley"

# Content details
puts comic.page_count   #=> 20
puts comic.genre        #=> "Superhero, Action, Adventure"
puts comic.language_iso #=> "en-US"
puts comic.format       #=> "Digital"

# Ratings and reviews
puts comic.age_rating       #=> "Teen"
puts comic.community_rating #=> 4.25

Convenience Methods

# Boolean helpers
puts comic.manga?           #=> false
puts comic.right_to_left?   #=> false
puts comic.black_and_white? #=> false

# Page information
puts comic.pages?       #=> true
puts comic.pages.length #=> 12

# Get specific page types
covers  = comic.cover_pages
stories = comic.story_pages

# Multi-value fields as arrays
characters = comic.characters #=> ["Spider-Man", "Peter Parker", ...]
teams      = comic.teams      #=> ["Avengers"]
locations  = comic.locations  #=> ["New York City", "Manhattan", ...]
genres     = comic.genres     #=> ["Superhero", "Action", "Adventure"]
web_urls   = comic.web_urls   #=> ["https://marvel.com/...", "https://comicvine.com/..."]

# Raw data methods for original comma-separated strings
genres_raw     = comic.genres_raw_data     #=> "Superhero, Action, Adventure"
characters_raw = comic.characters_raw_data #=> "Spider-Man, Peter Parker, J. Jonah Jameson, Aunt May"
story_arcs_raw = comic.story_arcs_raw_data #=> "Brand New Day, Spider-Island"

# Singular schema elements alias to plural arrays
genre          = comic.genre          #=> ["Superhero", "Action", "Adventure"] (same as genres)
story_arc      = comic.story_arc      #=> ["Brand New Day", "Spider-Island"] (same as story_arcs)
story_arc_num  = comic.story_arc_number #=> ["1", "5"] (same as story_arc_numbers)

Working with Pages

comic.pages.each do |page|
  puts "Page #{page.image}: #{page.type}"
  puts "  Double page: #{page.double_page?}"                    if page.double_page?
  puts "  Bookmark: #{page.bookmark}"                           if page.bookmarked?
  puts "  Dimensions: #{page.image_width}x#{page.image_height}" if page.dimensions_available?
end

# Page type checks
page = comic.pages.first
puts page.cover?   #=> true for FrontCover, BackCover, InnerCover
puts page.story?   #=> true for Story pages
puts page.deleted? #=> true for Deleted pages

Manga Support

# Load a manga ComicInfo file
manga = ComicInfo.load 'path/to/manga/ComicInfo.xml'

puts manga.title            #=> "้€ฒๆ’ƒใฎๅทจไบบ"
puts manga.series           #=> "Attack on Titan"
puts manga.manga            #=> "YesAndRightToLeft"
puts manga.right_to_left?   #=> true
puts manga.language_iso     #=> "ja-JP"
puts manga.black_and_white? #=> true
puts manga.black_and_white  #=> "Yes"

Error Handling

begin
  comic = ComicInfo.load('nonexistent.xml')
rescue ComicInfo::Errors::FileError => e
  puts "File error: #{e.message}"
rescue ComicInfo::Errors::ParseError => e
  puts "Parse error: #{e.message}"
rescue ComicInfo::Errors::InvalidEnumError => e
  puts "Invalid enum: #{e.field} = '#{e.value}', valid: #{e.valid_values}"
rescue ComicInfo::Errors::RangeError => e
  puts "Out of range: #{e.field} = #{e.value}, range: #{e.min}..#{e.max}"
rescue ComicInfo::Errors::TypeCoercionError => e
  puts "Type coercion error: #{e.message}"
end

Schema Support

This gem fully supports the ComicInfo v2.0 XSD schema with all field types:

String Fields

  • Title, Series, Number, Summary, Notes
  • Creator fields (Writer, Penciller, Inker, Colorist, Letterer, CoverArtist, Editor, Translator)
  • Publication fields (Publisher, Imprint, Web, LanguageISO, Format)
  • Character/Location fields (MainCharacterOrTeam)
  • Story fields (SeriesGroup, ScanInformation, Review)

Multi-value Fields (String + Array Access)

  • Genre/Genres: Raw comma-separated string + parsed array
  • Characters: Raw comma-separated string + parsed array
  • Teams: Raw comma-separated string + parsed array
  • Locations: Raw comma-separated string + parsed array
  • StoryArc/StoryArcs: Raw comma-separated string + parsed array
  • StoryArcNumber/StoryArcNumbers: Raw comma-separated string + parsed array

Integer Fields

  • Count, Volume, AlternateCount, PageCount
  • Date fields (Year, Month, Day)

Enum Fields

  • BlackAndWhite: "Unknown", "No", "Yes"
  • Manga: "Unknown", "No", "Yes", "YesAndRightToLeft"
  • AgeRating: Various ESRB and international ratings

Decimal Fields

  • CommunityRating: 0.0 to 5.0 range with validation

Complex Fields

  • Pages: Array of ComicPageInfo objects with full attribute support
  • Page types: FrontCover, BackCover, InnerCover, Roundup, Story, Advertisement, Editorial, Letters, Preview, Other, Deleted

Export Formats

  • JSON: Complete serialization with all fields
  • YAML: Human-readable format with array structures
  • XML: Valid ComicInfo v2.0 compliant XML generation
  • Hash: Ruby hash representation with symbol keys

Data Export & XML Generation

comic = ComicInfo.load 'path/to/ComicInfo.xml'

# Export as JSON
json_string = comic.to_json
puts JSON.pretty_generate(JSON.parse(json_string))

# Export as YAML
yaml_string = comic.to_yaml
puts yaml_string

# Generate XML
xml_string = comic.to_xml
puts xml_string

# Save to file
comic.save 'path/to/new/ComicInfo.xml'

# Save to IO object
File.open('path/to/new/ComicInfo.xml', 'w') do |file|
  comic.save file
end

# Export as Hash
hash = comic.to_h
puts hash[:title]                   #=> "The Amazing Spider-Man"
puts hash[:genre]                   #=> "Superhero, Action, Adventure" (raw data)
puts hash[:genres]                  #=> ["Superhero", "Action", "Adventure"] (parsed array)
puts hash[:genres_raw_data]         #=> "Superhero, Action, Adventure" (same as :genre)
puts hash[:characters]              #=> ["Spider-Man", "Peter Parker", ...]
puts hash[:characters_raw_data]     #=> "Spider-Man, Peter Parker, J. Jonah Jameson, Aunt May"
puts hash[:pages].length            #=> 12

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Running Tests

# Run all tests
bundle exec rspec

# Run with documentation format
bundle exec rspec --format documentation

# Run specific test file
bundle exec rspec spec/comic_info_spec.rb

Code Quality

# Run RuboCop linter
bundle exec rubocop

# Auto-fix correctable issues
bundle exec rubocop --autocorrect

Implementation Status

Current Features โœ…

  • Core Reading: Complete ComicInfo.xml parsing
  • XML Writing: Full ComicInfo.xml generation with round-trip consistency
  • Schema Compliance: Full ComicInfo v2.0 support
  • Field Types: String, Integer, Decimal, Enum, Boolean, Arrays
  • Multi-value Fields: Both string and array access methods
  • Issue &Page Support: Complete Issue and nested Page objects
  • Error Handling: Custom exceptions with detailed messages
  • Data Export: JSON, YAML, and XML serialization
  • Validation: Enum values, ranges, type coercion
  • Unicode Support: International characters and special symbols
  • Test Coverage: 178 comprehensive test cases

Planned Features ๐Ÿšง

  • CLI Tool: Command-line interface for file manipulation
  • Schema Migration: Support for multiple ComicInfo versions

Schema Versions

  • โœ… ComicInfo v2.0: Full support (current)
  • ๐Ÿšง ComicInfo v2.1: Planned
  • ๐Ÿšง ComicInfo v1.0: Planned

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/veganstraightedge/comicinfo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the ComicInfo project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

Acknowledgments