{"id":15510370,"url":"https://github.com/nowlinuxing/sumaki","last_synced_at":"2026-04-16T17:38:15.331Z","repository":{"id":65986795,"uuid":"603802306","full_name":"nowlinuxing/sumaki","owner":"nowlinuxing","description":"Sumaki is a wrapper for structured data like JSON.","archived":false,"fork":false,"pushed_at":"2024-06-06T03:54:50.000Z","size":96,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-28T17:49:20.260Z","etag":null,"topics":["ruby","rubygems","wrapper-library"],"latest_commit_sha":null,"homepage":"","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/nowlinuxing.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"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}},"created_at":"2023-02-19T16:08:13.000Z","updated_at":"2024-06-06T03:54:48.000Z","dependencies_parsed_at":"2024-04-23T07:50:50.686Z","dependency_job_id":null,"html_url":"https://github.com/nowlinuxing/sumaki","commit_stats":{"total_commits":9,"total_committers":1,"mean_commits":9.0,"dds":0.0,"last_synced_commit":"c856924934031cbd57bb81254be509557ac2c98f"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/nowlinuxing/sumaki","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nowlinuxing%2Fsumaki","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nowlinuxing%2Fsumaki/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nowlinuxing%2Fsumaki/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nowlinuxing%2Fsumaki/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nowlinuxing","download_url":"https://codeload.github.com/nowlinuxing/sumaki/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nowlinuxing%2Fsumaki/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275076086,"owners_count":25401311,"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","status":"online","status_checked_at":"2025-09-14T02:00:10.474Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["ruby","rubygems","wrapper-library"],"created_at":"2024-10-02T09:48:04.495Z","updated_at":"2026-04-16T17:38:10.276Z","avatar_url":"https://github.com/nowlinuxing.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sumaki\n\n---\n\n[![Gem Version](https://badge.fury.io/rb/sumaki.svg)](https://badge.fury.io/rb/sumaki)\n![example workflow](https://github.com/nowlinuxing/sumaki/actions/workflows/main.yml/badge.svg?branch=main)\n[![Maintainability](https://api.codeclimate.com/v1/badges/dd92d4092d6858cbcfb2/maintainability)](https://codeclimate.com/github/nowlinuxing/sumaki/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/dd92d4092d6858cbcfb2/test_coverage)](https://codeclimate.com/github/nowlinuxing/sumaki/test_coverage)\n\n**Sumaki** is a wrapper for structured data like JSON.\n\nSince Sumaki wraps the target data as it is, rather than parsing it using a schema, the original data can be referenced at any time.\n\nThis makes it easy to add or modify definitions as needed while checking the target data.\n\nThis feature may be useful when there is no document defining the structure of the data, or when the specification is complex and difficult to grasp, and the definition is written little by little starting from the obvious places.\n\n```ruby\nclass AnimeList\n  include Sumaki::Model\n  repeated :anime\n  field :name\n\n  class Anime\n    include Sumaki::Model\n    singular :studio\n    field :title\n\n    class Studio\n      include Sumaki::Model\n      field :name\n    end\n  end\nend\n\ndata = {\n  name: 'Winter 2023',\n  anime: [\n    {\n      title: 'The Vampire Dies in No Time',\n      studio: {\n        name: 'MADHOUSE Inc.'\n      }\n    },\n    {\n      title: '“Ippon” again!',\n      studio: {\n        name: 'BAKKEN RECORD'\n      }\n    }\n  ]\n}\n\nanime_list = AnimeList.new(data)\nanime_list.name #=\u003e 'Winter 2023'\nanime_list.anime[0].title #=\u003e 'The Vampire Dies in No Time'\nanime_list.anime[0].studio.name #=\u003e  'MADHOUSE Inc.'\nanime_list.anime[0].object #=\u003e { title: 'The Vampire Dies in No Time', studio: { name: 'MADHOUSE Inc.' } }\n```\n\n\n## Installation\n\nInstall the gem and add to the application's Gemfile by executing:\n\n    $ bundle add sumaki\n\nIf bundler is not being used to manage dependencies, install the gem by executing:\n\n    $ gem install sumaki\n\n## Usage\n\nInclude `Sumaki::Model` module in the class that wraps the data, and give the data when creating the instance.\n\n```ruby\nclass Anime\n  include Sumaki::Model\nend\n\nAnime.new({})\n```\n\nOnly this does not give access to fields or structured data, so the following declarations need to be added.\n\n### Access to the fields\n\nBy declaring `field`, you can access the field.\n\n```ruby\nclass Anime\n  include Sumaki::Model\n  field :title\n  field :url\nend\n```\n\n```ruby\n# Read the field values\nanime = Anime.new({ title: 'The Vampire Dies in No Time', url: 'https://sugushinu-anime.jp/' })\nanime.title #=\u003e 'The Vampire Dies in No Time'\nanime.url #=\u003e 'https://sugushinu-anime.jp/'\n```\n\n```ruby\n# Write the field value\nanime = Anime.new({})\nanime.title = 'The Vampire Dies in No Time'\nanime.title #=\u003e 'The Vampire Dies in No Time'\n```\n\nIf the data contains attributes not declared in the field, it raises no error and is simply ignored.\n\n#### Type casting\n\nWhen a type is specified, it will be typecast.\n\n```ruby\nclass Character\n  include Sumaki::Model\n\n  field :age, :int\nend\n\ncharacter = Character.new({ age: '208' })\ncharacter.age #=\u003e 208\n```\n\nTypes are:\n\n* `:int`\n* `:float`\n* `:string`\n* `:bool`\n* `:date`\n* `:datetime`\n\n### Access to the sub object\n\nBy declaring `singular`, you can access the sub object.\n\n```ruby\nclass Book\n  include Sumaki::Model\n  singular :company\n  field :title\n\n  class Company\n    include Sumaki::Model\n    field :name\n  end\nend\n```\n\n```ruby\ndata = {\n  title: 'The Ronaldo Chronicles',\n  company: {\n    name: 'Autumn Books',\n  }\n}\n\n# Read from the sub object\nbook = Book.new(data)\nbook.company.name #=\u003e 'Autumn Books'\n```\n\n```ruby\n# Build a sub object\nbook = Book.new({})\nbook.build_company(name: 'Autumn Books')\nbook.company #=\u003e #\u003cBook::Company:0x000073a618e31e80 name: \"Autumn Books\"\u003e\n```\n\nSub object is wrapped with the class inferred from the field name under the original class.\n\nThis can be changed by specifying the class to wrap.\n\n```ruby\nclass Book\n  include Sumaki::Model\n  singular :author, class_name: 'Character'\n  field :title\n\n  class Character\n    include Sumaki::Model\n    field :name\n  end\nend\n\ndata = {\n  title: 'The Ronaldo Chronicles',\n  author: {\n    name: 'Ronaldo'\n  }\n}\n\nbook = Book.new(data)\nbook.author.class #=\u003e Book::Character\n```\n\n### Access to the repeated sub objects\n\nBy declaring `repeated`, you can access the repeated sub objects as an Array.\n\n```ruby\nclass Company\n  include Sumaki::Model\n  repeated :member\n  field :name\n\n  class Member\n    include Sumaki::Model\n    field :name\n  end\nend\n```\n\n```ruby\ndata = {\n  name: 'The Ronaldo Vampire Hunter Agency',\n  member: [\n    { name: 'Ronaldo' },\n    { name: 'Draluc' },\n    { name: 'John' }\n  ]\n}\n\n# Read from the sub object\ncompany = Company.new(data)\ncompany.member.size #=\u003e 3\ncompany.member[2].name #=\u003e 'John'\n```\n\n```ruby\n# Build a sub object\ncompany = Company.new({})\ncompany.member.build(name: 'John')\ncompany.member[0].name #=\u003e 'John'\n```\n\nThe `class_name` option can also be used to specify the class to wrap.\n\n### Access to the parent object\n\nParent object can be referenced from sub object by `#parent` method.\n\n```ruby\nclass Character\n  include Sumaki::Model\n  singular :child\n  field :name\n\n  class Child\n    include Sumaki::Model\n    field :name\n  end\nend\n\ndata = {\n  name: 'Draus',\n  child: {\n    name: 'Draluc'\n  }\n}\n\ncharacter = Character.new(data)\ncharacter.child.name #=\u003e 'Draluc'\ncharacter.child.parent.name #=\u003e 'Draus'\n```\n\n### Enumerations\n\nBy declaring `enum`, You can map a field to the specified value.\n\n```ruby\nclass Character\n  include Sumaki::Model\n  field :name\n  enum :type, { vampire: 1, vampire_hunter: 2, familier: 3, editor: 4 }\nend\n```\n\n```ruby\ndata = {\n  name: 'John',\n  type: 3\n}\n\n# Read the enum\ncharacter = Character.new(data)\ncharacter.type.name #=\u003e :familier\ncharacter.type.familier? #=\u003e true\n```\n\n```ruby\n# Write the enum value\ncharacter = Character.new({})\ncharacter.type = 1\ncharacter.type.name #=\u003e :vampire\n\ncharacter.type = :vampire_hunter\ncharacter.type.name #=\u003e :vampire_hunter\n\ncharacter.type.familier!\ncharacter.type.name #=\u003e :familier\n```\n\n\n## Development\n\nAfter 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.\n\nTo 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](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/nowlinuxing/sumaki.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnowlinuxing%2Fsumaki","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnowlinuxing%2Fsumaki","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnowlinuxing%2Fsumaki/lists"}