Adding Formats

Parse and render support for JSON, CSV, XML, and similar data formats

=begin rakudoc

Overview

Formats convert between external data representations and Qwiratry-visible data. When a format produces custom tree nodes, add a tree navigator as a separate extension point.

Use this extension point when the new thing is a representation such as JSON, CSV, XML, YAML, TOML, binary encodings, or another parse/render representation. Do not use it for databases, APIs, filesystems, or other live sources and destinations; those belong in source/destination extensions.

To add support for a new format:

  • 1. Setup: choose the format name, module path, and META6.json entry.

  • 2. Parser: implement a parser if Qwiratry should receive that representation.

  • 3. Renderer: implement a renderer if Qwiratry should output that representation.

  • 4. Navigator: optionally add a tree navigator if the parsed data outputs custom tree nodes.

  • 5. Testing: test discovery, parsing, rendering, navigation, and missing-format errors.

The current base parser receives a Str because the existing formats are text-like, but the extension model is about data representations in general. Future base classes or overloads may support binary blobs or other non-text payloads.

Setup

Choose The Format Name

Choose the format name that callers will use, such as JSON, CSV, or CBOR. Format names are normalized by Qwiratry::Format, so callers may use labels like json while the module remains named JSON.

Add The Module

Add a module under lib/Qwiratry/Format/ named for that format.

A format module is named:

Qwiratry::Format::<FORMAT>

It defines one or more operation classes:

Qwiratry::Format::<FORMAT>::Parse
Qwiratry::Format::<FORMAT>::Render

For example, the built-in demonstration formats use *demo names to make it clear that they are not complete production parsers:

Qwiratry::Format::JSONdemo::Parse
Qwiratry::Format::JSONdemo::Render

Formats that parse into ordinary Raku data (eg. Positional/Associative) usually do not need a tree navigator.

Update META6

Add the format module to META6.json provides so discovery can load it.

"Qwiratry::Format::Example": "lib/Qwiratry/Format/Example.rakumod"

Parser

Parser Contract

Qwiratry::Format::Base::Parse is the base class for parsers. A custom parser inherits from this and currently implements parse(Str $input-string -- Mu)>.

Minimal Parser Example

use Qwiratry::Format::Base;

class Qwiratry::Format::Example::Parse is Qwiratry::Format::Base::Parse {
    method parse(Str $input-data --> Mu) {
        %(raw => $input-data)
    }
}

Renderer

Renderer Contract

Qwiratry::Format::Base::Render is the base class for renderers. A custom renderer inherits from this and implements render(Mu $data, Associative :%options -- Str)>.

Minimal Renderer Example

use Qwiratry::Format::Base;

class Qwiratry::Format::Example::Render is Qwiratry::Format::Base::Render {
    method render(Mu $data, Associative :%options --> Str) {
        $data.raku
    }
}

Tree Navigator

A format may need a Qwiratry::Tree::Navigator::<NAVIGATOR> module when its parser emits a custom tree-shaped object model.

Navigators are documented in Adding Tree Navigators. Use a navigator when the generic tree walker is still the right traversal engine, but Qwiratry needs format-specific child, parent, or attribute access.

A tree navigator does not need a matching Parse or Render class. For example, RakuAST is represented only as Qwiratry::Tree::Navigator::RakuAST because the Raku compiler owns parsing and rendering.

Testing

Add tests that prove:

  • Qwiratry::Format.formats(:type<Parse>) discovers the parser.

  • Qwiratry::Format.formats(:type<Render>) discovers the renderer.

  • Qwiratry::Format.make(:type<Parse>, :format<FORMAT>) returns a parser.

  • Qwiratry::Format.make(:type<Render>, :format<FORMAT>) returns a renderer.

  • Qwiratry::Tree::Navigator.navigators discovers any navigator needed for custom tree nodes.

  • Parse operators accept the new format.

  • Render operators accept the new format.

  • Missing formats throw X::Qwiratry::Format::NotFound.

Reference Material

Main Types

  • Qwiratry::Format

Factory and discovery service for parse and render implementations.

  • Qwiratry::Format::Base::Parse

Base class for parsers. A custom parser inherits from this and currently implements parse(Str $input-string -- Mu)>.

  • Qwiratry::Format::Base::Render

Base class for renderers. A custom renderer inherits from this and implements render(Mu $data, Associative :%options -- Str)>.

  • Qwiratry::Tree::Navigator::Base

Role for tree navigators. A custom navigator does this and implements the required tree access methods.

  • X::Qwiratry::Format::NotFound

Thrown when parse or render operators request a format that cannot be found.

Discovery

Qwiratry::Format discovers modules under Qwiratry::Format::* and checks whether the requested operation class inherits from the matching base class.

my @parse-formats = Qwiratry::Format.formats(:type<Parse>);
my @render-formats = Qwiratry::Format.formats(:type<Render>);

my $parser = Qwiratry::Format.make(:type<Parse>, :format<JSONdemo>);
my $renderer = Qwiratry::Format.make(:type<Render>, :format<JSONdemo>);

=end rakudoc

Qwiratry v0.0.9

Declarative query and data-walking architecture for Raku, with transformers, molds, walkers, and I/O pipelines.

Authors

  • Tim Nelson

License

Dependencies

SlangifyImplementation::Loader:ver<0.0.9+>Glob::Grammar

Test Dependencies

Provides

  • Qwiratry
  • Qwiratry::Context
  • Qwiratry::Format
  • Qwiratry::Format::Base
  • Qwiratry::Format::CSVdemo
  • Qwiratry::Format::JSONdemo
  • Qwiratry::Location
  • Qwiratry::Location::Base
  • Qwiratry::Location::File
  • Qwiratry::Mold
  • Qwiratry::Mold::Compiler
  • Qwiratry::Mold::Registry
  • Qwiratry::Mold::Slang
  • Qwiratry::Operator::Capability
  • Qwiratry::Operator::IO
  • Qwiratry::Operator::MapReduce
  • Qwiratry::Operator::Navigation
  • Qwiratry::Operator::Set
  • Qwiratry::Query::Evaluator::Eager
  • Qwiratry::Query::Evaluator::Filter
  • Qwiratry::Query::Evaluator::Join
  • Qwiratry::Query::Evaluator::Lazy
  • Qwiratry::Query::Evaluator::MapReduce
  • Qwiratry::Query::Evaluator::Navigation
  • Qwiratry::Query::Evaluator::Relational
  • Qwiratry::Query::Evaluator::Row
  • Qwiratry::Query::Evaluator::Set
  • Qwiratry::Query::Evaluator::Union
  • Qwiratry::Query::Extract
  • Qwiratry::Query::NamedJoins
  • Qwiratry::Query::RelationCommon
  • Qwiratry::Query::Runtime
  • Qwiratry::Query::Selector
  • Qwiratry::Query::Slang
  • Qwiratry::Query::Specificity
  • Qwiratry::Query::Topic
  • Qwiratry::QueryIterator
  • Qwiratry::QueryMatch
  • Qwiratry::Setup
  • Qwiratry::Strategy
  • Qwiratry::Strategy::ControlSignal
  • Qwiratry::Strategy::FinishResult
  • Qwiratry::Strategy::RewriteSpec
  • Qwiratry::Strategy::Traversal
  • Qwiratry::Suggest
  • Qwiratry::Table
  • Qwiratry::Table::Schema
  • Qwiratry::Transformer
  • Qwiratry::Transformer::Copy
  • Qwiratry::Transformer::TreeRewrite
  • Qwiratry::Tree::Navigator
  • Qwiratry::Tree::Navigator::Base
  • Qwiratry::Tree::Navigator::Filesystem
  • Qwiratry::Tree::Navigator::Match
  • Qwiratry::Tree::Navigator::RakuAST
  • Qwiratry::Tree::Replace
  • Qwiratry::Walker
  • Qwiratry::Walker::Capabilities
  • Qwiratry::Walker::Factory
  • Qwiratry::Walker::Implementation::Table
  • Qwiratry::Walker::Implementation::Tree
  • Qwiratry::Walker::Master
  • Qwiratry::Walker::Providing
  • X::Qwiratry

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.