{"id":26733444,"url":"https://github.com/amcaplan/persistent_open_struct","last_synced_at":"2026-03-11T02:01:13.141Z","repository":{"id":31999397,"uuid":"35570274","full_name":"amcaplan/persistent_open_struct","owner":"amcaplan","description":"The flexibility of OpenStruct, at 1/5 (not 1/25) the speed of a regular Ruby class","archived":false,"fork":false,"pushed_at":"2016-07-12T22:24:54.000Z","size":18,"stargazers_count":16,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T01:52:32.802Z","etag":null,"topics":[],"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/amcaplan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-13T19:37:03.000Z","updated_at":"2017-11-09T23:24:45.000Z","dependencies_parsed_at":"2022-08-21T00:20:57.677Z","dependency_job_id":null,"html_url":"https://github.com/amcaplan/persistent_open_struct","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amcaplan%2Fpersistent_open_struct","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amcaplan%2Fpersistent_open_struct/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amcaplan%2Fpersistent_open_struct/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amcaplan%2Fpersistent_open_struct/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amcaplan","download_url":"https://codeload.github.com/amcaplan/persistent_open_struct/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248883070,"owners_count":21177147,"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":[],"created_at":"2025-03-28T01:49:26.446Z","updated_at":"2026-03-11T02:01:07.999Z","avatar_url":"https://github.com/amcaplan.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Gem Version](https://badge.fury.io/rb/persistent_open_struct.svg)](http://badge.fury.io/rb/persistent_open_struct)\n![Travis badge](https://travis-ci.org/amcaplan/persistent_open_struct.svg?branch=master)\n\n# PersistentOpenStruct\n\nAre you inserting data in the same format into `OpenStruct` again and again?\nWish `OpenStruct` wouldn't have to define a new singleton method on each\nindividual object?  Here is your solution!\n\n`PersistentOpenStruct` defines methods on the class, so as long as you keep using\nthe same keys, no new methods will be defined.  The class quickly learns the\nshape of your data, so you can use it with minimal overhead.  (Though of course\nit's still not as fast as doing the work of defining a full-fledged class.)\n\nIt obeys the entire interface of `OpenStruct`, so you can insert it into your code\nwithout problem!  (Unless you're using `OpenStruct#delete_field` for some reason;\n`PersistentOpenStruct` refuses to undefine the methods it defines.)\n\nThis gives a noticeable performance boost.  Here are the results of the\nbenchmark found at\n[`benchmark/benchmark.rb`](http://github.com/amcaplan/persistent_open_struct/blob/master/benchmark/benchmark.rb)\nrun on Ruby 2.3.1; the final benchmark is most representative of the average case.\n\nAlso included are results for\n[`OpenFastStruct`](http://github.com/arturoherrero/ofstruct) as well, to get a\nsense of alternative solutions.\n\nMore is better.\n\n```\n$ ruby benchmark/benchmark.rb\nInitialization benchmark\n\nWarming up --------------------------------------\n          OpenStruct    88.289k i/100ms\nPersistentOpenStruct    78.440k i/100ms\n      OpenFastStruct    81.306k i/100ms\n        RegularClass   200.536k i/100ms\nCalculating -------------------------------------\n          OpenStruct    981.150k (± 7.8%) i/s -      4.944M in   5.069950s\nPersistentOpenStruct    898.432k (± 9.5%) i/s -      4.471M in   5.022044s\n      OpenFastStruct      1.059M (± 5.6%) i/s -      5.366M in   5.086061s\n        RegularClass      3.860M (± 9.6%) i/s -     19.251M in   5.034804s\n\nComparison:\n        RegularClass:  3859650.0 i/s\n      OpenFastStruct:  1058578.4 i/s - 3.65x slower\n          OpenStruct:   981149.5 i/s - 3.93x slower\nPersistentOpenStruct:   898431.6 i/s - 4.30x slower\n\n\n\nAssignment Benchmark\n\nWarming up --------------------------------------\n          OpenStruct   199.451k i/100ms\nPersistentOpenStruct   214.181k i/100ms\n      OpenFastStruct    99.324k i/100ms\n        RegularClass   312.190k i/100ms\nCalculating -------------------------------------\n          OpenStruct      4.505M (± 5.4%) i/s -     22.538M in   5.019146s\nPersistentOpenStruct      4.375M (± 4.2%) i/s -     21.846M in   5.002085s\n      OpenFastStruct      1.405M (± 5.0%) i/s -      7.052M in   5.033620s\n        RegularClass     11.113M (± 5.2%) i/s -     55.570M in   5.015664s\n\nComparison:\n        RegularClass: 11112511.1 i/s\n          OpenStruct:  4504735.3 i/s - 2.47x slower\nPersistentOpenStruct:  4375412.9 i/s - 2.54x slower\n      OpenFastStruct:  1404724.1 i/s - 7.91x slower\n\n\n\nAccess Benchmark\n\nWarming up --------------------------------------\n          OpenStruct   256.277k i/100ms\nPersistentOpenStruct   259.536k i/100ms\n      OpenFastStruct   227.602k i/100ms\n        RegularClass   260.242k i/100ms\nCalculating -------------------------------------\n          OpenStruct      6.798M (± 5.0%) i/s -     34.085M in   5.027391s\nPersistentOpenStruct      6.539M (± 6.0%) i/s -     32.702M in   5.019393s\n      OpenFastStruct      4.875M (± 4.0%) i/s -     24.353M in   5.004194s\n        RegularClass      6.654M (± 4.7%) i/s -     33.311M in   5.018183s\n\nComparison:\n          OpenStruct:  6797834.1 i/s\n        RegularClass:  6653907.4 i/s - same-ish: difference falls within error\nPersistentOpenStruct:  6538883.0 i/s - same-ish: difference falls within error\n      OpenFastStruct:  4875059.7 i/s - 1.39x slower\n\n\n\nAll-Together benchmark\n\nWarming up --------------------------------------\n          OpenStruct    14.490k i/100ms\nPersistentOpenStruct    63.043k i/100ms\n      OpenFastStruct    47.777k i/100ms\n        RegularClass   197.293k i/100ms\nCalculating -------------------------------------\n          OpenStruct    155.130k (± 4.5%) i/s -    782.460k in   5.054693s\nPersistentOpenStruct    764.359k (± 6.6%) i/s -      3.846M in   5.053760s\n      OpenFastStruct    546.809k (± 4.7%) i/s -      2.771M in   5.079275s\n        RegularClass      3.674M (± 9.1%) i/s -     18.348M in   5.054680s\n\nComparison:\n        RegularClass:  3673779.6 i/s\nPersistentOpenStruct:   764359.4 i/s - 4.81x slower\n      OpenFastStruct:   546808.8 i/s - 6.72x slower\n          OpenStruct:   155130.1 i/s - 23.68x slower\n```\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n    gem 'persistent_open_struct'\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install persistent_open_struct\n\n## Usage\nNote: requires Ruby 2.1.0 or above.\n\n``` ruby\nclass MyDataStructure \u003c PersistentOpenStruct\nend\n\ndatum1 = MyDataStructure.new(foo: :bar)\n\ndatum2 = MyDataStructure.new\ndatum2.respond_to?(:baz) #=\u003e false\ndatum2.respond_to?(:foo) #=\u003e true\n```\n\n## Contributing\n\n1. Fork it ( https://github.com/amcaplan/persistent_open_struct/fork )\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\nChanges to functionality require testing.  Performance improvements should\ninclude before/after benchmarks (or ideally just update the results in the\nREADME above).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famcaplan%2Fpersistent_open_struct","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famcaplan%2Fpersistent_open_struct","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famcaplan%2Fpersistent_open_struct/lists"}