{"id":18103974,"url":"https://github.com/svoop/aixm","last_synced_at":"2025-04-13T19:30:28.707Z","repository":{"id":62553096,"uuid":"115747227","full_name":"svoop/aixm","owner":"svoop","description":"Partial implementation of AIXM (Aeronautical Information Exchange Model) and OFMX (Open FlightMaps eXchange) for Ruby","archived":false,"fork":false,"pushed_at":"2024-12-27T09:35:13.000Z","size":1649,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-27T10:08:36.232Z","etag":null,"topics":["aviation","gem","openflightmaps","ruby"],"latest_commit_sha":null,"homepage":"https://bitcetera.com","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/svoop.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"svoop","custom":"https://donorbox.org/bitcetera"}},"created_at":"2017-12-29T19:03:32.000Z","updated_at":"2024-12-27T09:35:09.000Z","dependencies_parsed_at":"2023-02-12T17:16:02.036Z","dependency_job_id":"55e47ef3-cc19-40cb-bb71-b0796cc5ff1c","html_url":"https://github.com/svoop/aixm","commit_stats":{"total_commits":473,"total_committers":2,"mean_commits":236.5,"dds":0.04016913319238902,"last_synced_commit":"1b54981cd392732f51ad3e19175423c9c08ebcd5"},"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svoop%2Faixm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svoop%2Faixm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svoop%2Faixm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svoop%2Faixm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/svoop","download_url":"https://codeload.github.com/svoop/aixm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248767751,"owners_count":21158525,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aviation","gem","openflightmaps","ruby"],"created_at":"2024-10-31T22:13:39.800Z","updated_at":"2025-04-13T19:30:28.681Z","avatar_url":"https://github.com/svoop.png","language":"Ruby","funding_links":["https://github.com/sponsors/svoop","https://donorbox.org/bitcetera"],"categories":[],"sub_categories":[],"readme":"[![Version](https://img.shields.io/gem/v/aixm.svg?style=flat)](https://rubygems.org/gems/aixm)\n[![Tests](https://img.shields.io/github/actions/workflow/status/svoop/aixm/test.yml?style=flat\u0026label=tests)](https://github.com/svoop/aixm/actions?workflow=Test)\n[![Code Climate](https://img.shields.io/codeclimate/maintainability/svoop/aixm.svg?style=flat)](https://codeclimate.com/github/svoop/aixm/)\n[![GitHub Sponsors](https://img.shields.io/github/sponsors/svoop.svg)](https://github.com/sponsors/svoop)\n\n# AIXM\n\nPartial implementation of the [Aeronautical Information Exchange Model (AIXM 4.5)](http://aixm.aero) and it's dialect [Open FlightMaps eXchange format (OFMX 0)](https://gitlab.com/openflightmaps/ofmx/wikis) for Ruby.\n\nFor now, only the parts needed to automize the AIP import of [open flightmaps](https://openflightmaps.org) are part of this gem. Most notably, the gem is only a builder for snapshot files and does not parse them.\n\n* [Homepage](https://github.com/svoop/aixm)\n* [API](https://www.rubydoc.info/gems/aixm)\n* Author: [Sven Schwyn - Bitcetera](https://bitcetera.com)\n\nThank you for supporting free and open-source software by sponsoring on [GitHub](https://github.com/sponsors/svoop) or on [Donorbox](https://donorbox.com/bitcetera). Any gesture is appreciated, from a single Euro for a ☕️ cup of coffee to 🍹 early retirement.\n\n## Install\n\n### Security\n\nThis gem is [cryptographically signed](https://guides.rubygems.org/security/#using-gems) in order to assure it hasn't been tampered with. Unless already done, please add the author's public key as a trusted certificate now:\n\n```\ngem cert --add \u003c(curl -Ls https://raw.github.com/svoop/aixm/main/certs/svoop.pem)\n```\n\n### Bundler\n\nAdd the following to the \u003ctt\u003eGemfile\u003c/tt\u003e or \u003ctt\u003egems.rb\u003c/tt\u003e of your [Bundler](https://bundler.io) powered Ruby project:\n\n```ruby\ngem 'aixm'\n```\n\nAnd then install the bundle:\n\n```\nbundle install --trust-policy MediumSecurity\n```\n\n### Standalone\n\nIf you're only going to use [the executables](#executables), make sure to have the [latest version of Ruby](https://www.ruby-lang.org/en/documentation/installation/) and then install this gem:\n\n```\ngem install aixm --trust-policy MediumSecurity\n```\n\n## Usage\n\nHere's how to build a document object, populate it with a simple feature and then render it as AIXM or OFMX:\n\n```ruby\ndocument = AIXM.document(\n  region: 'LF'\n)\ndocument.add_feature(\n  AIXM.designated_point(\n    id: \"ABIXI\",\n    xy: AIXM.xy(lat: %q(46°31'54.3\"N), long: %q(002°19'55.2\"W)),\n    type: :icao\n  )\n)\nAIXM.ofmx!\ndocument.to_xml\n```\n\nYou can initialize all elements either traditionally or by use of the corresponding shorthand AIXM class method. The following two statements are identical:\n\n```ruby\nAIXM::Feature::NavigationalAid::DesignatedPoint.new(...)\nAIXM.designated_point(...)\n```\n\nSee `AIXM::CLASSES` for the complete list of shorthand names.\n\n## Configuration\n\n### AIXM.config.schema\n\nThe schema is either `:aixm` (default) or `:ofmx`:\n\n```ruby\nAIXM.config.schema = :ofmx   # =\u003e:ofmx\n```\n\nThere are shortcuts to set and get the schema:\n\n```ruby\nAIXM.schema             # =\u003e :aixm\nAIXM.aixm?              # =\u003e true\nAIXM.ofmx!              # =\u003e :ofmx\nAIXM.ofmx?              # =\u003e true\nAIXM.schema             # =\u003e :ofmx\nAIXM.schema(:version)   # =\u003e 0\n```\n\n### AIXM.config.region\n\nThe `:ofmx` schema requires the [region to be set on all core features](https://gitlab.com/openflightmaps/ofmx/wikis/Features#core-features). You can do so on individual features, however, you might want to configure a default region to simplify your life:\n\n```ruby\nAIXM.ofmx!\nAIXM.config.region = 'LF'\n```\n\n:warning: This setting has no effect when using the `:aixm` schema.\n\n### AIXM.voice_channel_separation\n\nDefine which voice channel separation should be used to validate voice communication frequencies.\n\n```ruby\nAIXM.voice_channel_separation = :any   # both 25 and 8.33 kHz (default)\nAIXM.voice_channel_separation = 25     # 25 kHz only\nAIXM.voice_channel_separation = 833    # 8.33 kHz only\n```\n\n### AIXM.config.mid\n\nIn order to insert [OFMX-compliant `mid` attributes](https://gitlab.com/openflightmaps/ofmx/wikis/Features#mid) into all `*Uid` elements, you have set the mid configuration option to `true`.\n\n```ruby\nAIXM.ofmx!\nAIXM.config.mid = false   # don't insert mid attributes (default)\nAIXM.config.mid = true    # insert mid attributes\n```\n\n:warning: This setting has no effect when using the `:aixm` schema.\n\n### AIXM.config.ignored_errors\n\nIn case you want to ignore certain XML schema validation errors, set this configuration option to a regular expression which matches the error messages to ignore. By default, no errors are ignored.\n\n```ruby\nAIXM.config.ignored_errors = /invalid date/i\n```\n\n## Models\n\n### Fundamentals\n* [Document](https://www.rubydoc.info/gems/aixm/AIXM/Document.html)\n* [A (angle)](https://www.rubydoc.info/gems/aixm/AIXM/A.html)\n* [D (dimension, distance or length)](https://www.rubydoc.info/gems/aixm/AIXM/D.html)\n* [F (frequency)](https://www.rubydoc.info/gems/aixm/AIXM/F.html)\n* [P (pressure)](https://www.rubydoc.info/gems/aixm/AIXM/P.html)\n* [R (rectangle)](https://www.rubydoc.info/gems/aixm/AIXM/R.html)\n* [XY (longitude and latitude)](https://www.rubydoc.info/gems/aixm/AIXM/XY.html)\n* [Z (height, elevation or altitude)](https://www.rubydoc.info/gems/aixm/AIXM/Z.html)\n\n### Features\n* [Address](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Address.html)\n* [Airport](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Airport.html)\n* [Airspace](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Airspace.html)\n* [Navigational aid](https://www.rubydoc.info/gems/aixm/AIXM/NavigationalAid.html)\n  * [Designated point](https://www.rubydoc.info/gems/aixm/AIXM/Feature/DesignatedPoint.html)\n  * [DME](https://www.rubydoc.info/gems/aixm/AIXM/Feature/DME.html)\n  * [Marker](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Marker.html)\n  * [NDB](https://www.rubydoc.info/gems/aixm/AIXM/Feature/NDB.html)\n  * [TACAN](https://www.rubydoc.info/gems/aixm/AIXM/Feature/TACAN.html)\n  * [VOR](https://www.rubydoc.info/gems/aixm/AIXM/Feature/VOR.html)\n* [Obstacle](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Obstacle.html)\n* [Obstacle group](https://www.rubydoc.info/gems/aixm/AIXM/Feature/ObstacleGroup.html)\n* [Organisation](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Organisation.html)\n* [Service](https://www.rubydoc.info/gems/aixm/AIXM/Component/Service.html)\n* [Unit](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Unit.html)\n* [Generic](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Generic.html)\n\n### Components\n\n* [ApproachLighting](https://www.rubydoc.info/gems/aixm/AIXM/Component/ApproachLighting.html)\n* [FATO](https://www.rubydoc.info/gems/aixm/AIXM/Component/FATO.html)\n* [Frequency](https://www.rubydoc.info/gems/aixm/AIXM/Component/Frequency.html)\n* [Geometry](https://www.rubydoc.info/gems/aixm/AIXM/Component/Geometry.html)\n  * [Arc](https://www.rubydoc.info/gems/aixm/AIXM/Component/Arc.html)\n  * [Border](https://www.rubydoc.info/gems/aixm/AIXM/Component/Border.html)\n  * [Circle](https://www.rubydoc.info/gems/aixm/AIXM/Component/Circle.html)\n  * [Point](https://www.rubydoc.info/gems/aixm/AIXM/Component/Point.html)\n  * [RhumbLine](https://www.rubydoc.info/gems/aixm/AIXM/Component/RhumbLine.html)\n* [Helipad](https://www.rubydoc.info/gems/aixm/AIXM/Component/Helipad.html)\n* [Layer](https://www.rubydoc.info/gems/aixm/AIXM/Component/Layer.html)\n* [Lighting](https://www.rubydoc.info/gems/aixm/AIXM/Component/Lighting.html)\n* [Runway](https://www.rubydoc.info/gems/aixm/AIXM/Component/Runway.html)\n* [Service](https://www.rubydoc.info/gems/aixm/AIXM/Component/Service.html)\n* [Surface](https://www.rubydoc.info/gems/aixm/AIXM/Component/Surface.html)\n* [Timetable](https://www.rubydoc.info/gems/aixm/AIXM/Component/Timetable.html)\n* [Timesheet](https://www.rubydoc.info/gems/aixm/AIXM/Component/Timesheet.html)\n* [VASIS](https://www.rubydoc.info/gems/aixm/AIXM/Component/VASIS.html)\n* [Vertical limit](https://www.rubydoc.info/gems/aixm/AIXM/Component/VerticalLimit.html)\n\n### Schedule\n\n* [Date](https://www.rubydoc.info/gems/aixm/AIXM/Schedule/Date.html)\n* [Day](https://www.rubydoc.info/gems/aixm/AIXM/Schedule/Day.html)\n* [Time](https://www.rubydoc.info/gems/aixm/AIXM/Schedule/Time.html)\n* [DateTime](https://www.rubydoc.info/gems/aixm/AIXM/Schedule/DateTime.html)\n\n## Associations\n\nThe different models are interwoven with [`has_many` and `has_one` associations](https://www.rubydoc.info/gems/aixm/AIXM/Association).\n\nPlease note that `has_many` associations are instances `AIXM::Concerns::Association::Array` which mostly behave like normal arrays. However, you must not add or remove elements on the array directly but use the corresponding method on the associating model instead:\n\n```ruby\ndocument.features \u003c\u003c airport   # =\u003e NoMethodError\ndocument.add_feature airport   # okay\n```\n\n### find_by and find\n\nUse `find_by` on `has_many` to filter associations by class and optional attribute values:\n\n```ruby\ndocument.features.find_by(:airport)               # =\u003e [#\u003cAIXM::Feature::Airport\u003e, #\u003cAIXM::Feature::Airport\u003e]\ndocument.features.find_by(:airport, id: 'LFNT')   # =\u003e [#\u003cAIXM::Feature::Airport\u003e]\n```\n\nTo search a `has_many` association for equal objects, use `find`:\n\n```ruby\ndocument.features.find(airport)   # =\u003e [#\u003cAIXM::Feature::Airport\u003e]\n```\n\nThis may seem redundant at first, but keep in mind that two instances of +AIXM::CLASSES+ which implement `#to_uid` are considered equal if they are instances of the same class and both their UIDs as calculated by `#to_uid` are equal. Attributes which are not part of the `#to_uid` calculation are irrelevant!\n\n### meta\n\nYou can write arbitrary meta information to any feature or component. It won't be used when building the AIXM or OFMX document, in fact, it is not used by this gem at all. But you can store e.g. foreign keys and then later use them to find a feature or component like so:\n\n```ruby\ndocument.features.find_by(:airport, meta: 1234)   # 1234 is the foreign key\n```\n\n### duplicates\n\nEqually on `has_many` associations, use `duplicates` to find identical or equal associations:\n\n```ruby\ndocument.features.duplicates   # =\u003e [#\u003cAIXM::Feature::Unit\u003e, #\u003cAIXM::Component::Service\u003e, ...]\n```\n\n## XML Comments\n\nAll features implement the `comment` attribute which accepts any object and converts it `#to_s`. When set, an XML comment is inserted right after the opening tag of the feature. This comes in handy e.g. in case you want to include source data facsimile such as NOTAM. Oneline and multiline comments are inserted differently:\n\n```xml\n\u003cAse\u003e\n  \u003c!--\n    B0330/22 NOTAMR B1756/21\n    Q) LSAS/QAFLT/V/NBO/E/000/050/4734N00841E005\n    A) LSAS B) 2203170746 C) 2206242359 EST\n  --\u003e\n  \u003cAseUid\u003e\n    \u003ccodeType\u003eRAS\u003c/codeType\u003e\n    \u003ccodeId\u003eB0330/22\u003c/codeId\u003e\n  \u003c/AseUid\u003e\n  (...)\n\u003c/Ase\u003e\n\n\u003cOrg\u003e\n  \u003c!-- Generic organisation --\u003e\n  \u003cOrgUid\u003e\n    \u003ctxtName\u003eFRANCE\u003c/txtName\u003e\n  \u003c/OrgUid\u003e\n  (...)\n\u003c/Org\u003e\n```\n\n## Payload Hash\n\nOFMX defines a [payload hash function](https://gitlab.com/openflightmaps/ofmx/wikis/Functions) used to facilitate association and modification tracking. It is used internally, but you can also use it in your own code:\n\n```ruby\n# Payload hash of XML fragment string\nxml = '\u003cxml\u003e\u003ca\u003e\u003c/a\u003e\u003c/xml\u003e'\nAIXM::PayloadHash.new(xml).to_uuid\n\n# Payload hash of Nokogiri XML fragment\ndocument = File.open(\"file.xml\") { Nokogiri::XML(_1) }\nAIXM::PayloadHash.new(document).to_uuid\n```\n\n## Validation\n\n`AIXM::Document#valid?` validates the resulting AIXM or OFMX against its XML schema. If any, you find the errors in `AIXM::Document#errors`.\n\n## Refinements\n\nBy `using AIXM::Refinements` you get a few handy [extensions to Ruby core classes](https://www.rubydoc.info/gems/aixm/AIXM/Refinements.html).\n\n## Executables\n\n### mkmid\n\nThe `mkmid` executable reads OFMX files, adds [OFMX-compliant `mid` values](https://gitlab.com/openflightmaps/ofmx/wikis/Features#mid) into all `*Uid` elements and validates the result against the schema.\n\n```\nmkmid --help\n```\n\n### ckmid\n\nThe `chmid` executable reads OFMX files, validates them against the schema and checks all `mid` attributes for [OFMX-compliance](https://gitlab.com/openflightmaps/ofmx/wikis/Features#mid).\n\n```\nckmid --help\n```\n\n## References\n\n### AIXM\n* [AIXM](http://aixm.aero)\n* [AICM 4.5 documentation](https://openflightmaps.gitlab.io/ofmx/aixm/4.5/manual/aicm/)\n* [AICM 4.5 manual](https://www.aixm.aero/sites/aixm.aero/files/imce/library/aicm_manual_4-5.pdf)\n* [AIXM 4.5 specification](http://aixm.aero/document/aixm-45-specification)\n\n### OFMX\n* [OFMX](https://gitlab.com/openflightmaps/ofmx)\n* [OFMX documentation](https://gitlab.com/openflightmaps/ofmx/wikis)\n* [open flightmaps](https://openflightmaps.org)\n\n## Tests\n\nSome tests are very time consuming and therefore skipped by default. To run the full test suite, set the environment variable:\n\n```\nexport SPEC_SCOPE=all\n```\n\n## Development\n\nTo install the development dependencies and then run the test suite:\n\n```\nbundle install\nbundle exec rake    # run tests once\nbundle exec guard   # run tests whenever files are modified\n```\n\nYou're welcome to [submit issues](https://github.com/svoop/aixm/issues) and contribute code by [forking the project and submitting pull requests](https://docs.github.com/en/get-started/quickstart/fork-a-repo).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvoop%2Faixm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsvoop%2Faixm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvoop%2Faixm/lists"}