{"id":17942639,"url":"https://github.com/petercamilleri/full_dup","last_synced_at":"2025-03-24T14:32:46.415Z","repository":{"id":56847825,"uuid":"56250074","full_name":"PeterCamilleri/full_dup","owner":"PeterCamilleri","description":"A recursive, deep copy version of dup with exclusion control and tolerance of non-dupable values.","archived":false,"fork":false,"pushed_at":"2021-05-19T19:31:34.000Z","size":33,"stargazers_count":3,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-26T21:47:44.837Z","etag":null,"topics":["deep","gem","ruby","rubygem","safe","utility"],"latest_commit_sha":null,"homepage":null,"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/PeterCamilleri.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-14T15:45:18.000Z","updated_at":"2023-03-05T04:20:47.000Z","dependencies_parsed_at":"2022-09-09T01:00:45.516Z","dependency_job_id":null,"html_url":"https://github.com/PeterCamilleri/full_dup","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterCamilleri%2Ffull_dup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterCamilleri%2Ffull_dup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterCamilleri%2Ffull_dup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterCamilleri%2Ffull_dup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PeterCamilleri","download_url":"https://codeload.github.com/PeterCamilleri/full_dup/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245289786,"owners_count":20591133,"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":["deep","gem","ruby","rubygem","safe","utility"],"created_at":"2024-10-29T03:06:34.785Z","updated_at":"2025-03-24T14:32:46.152Z","avatar_url":"https://github.com/PeterCamilleri.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FullDup\n\nThe full_dup gem adds the full_dup method to all objects descended from the\nObject class. While this gem makes extensive use of monkey patching, it does\nnot modify the behaviour of any existing methods. This is done to minimize\nthe risk of breaking any existing code.\n\nNew for version 0.0.6, now 84% faster (at least in my tests).\n\nThe standard dup method creates a fresh instance of most (non-scalar) objects\nbut does not process internal state. This internal state remains aliased in the\nduplicated copy. The full_dup method digs deep and makes copies of these\ninternal variables, not just arrays and hashes. It also allows classes to\nspecify an exclusion list of variables that are not to be processed.\n\nThis comprehensive approach creates another issue to be resolved. In Ruby, if an\nattempt is made to dup an immutable data item like a number, an error occurs.\nThe justification for this uncharacteristic strictness is not at all clear, but\nit does mean that the dup operation must be applied with great care.\n\nUnlike the standard dup method, the full\\_dup method does not throw an\nexception when it sees un-duppable value objects like 42 or true. These values\nsimply return themselves. This is deemed correct because those types of objects\nare immutable and do not need to be duped. Instead of raising an exception,\nthe code returns the immutable object instead.\n\nAnother issue that this gem deals with is that of data with looping reference\nchains. To handle this, the code tracks object ID values and does not re-dup\ndata that has already been duped. Thus even nasty edge cases are handled\nwithout any special effort on the part of the application programmer. Note though\nthat this also means that it is important that the object id be correctly\nimplemented. Fortunately, this is done by default in Ruby.\n\nIf you wish to implement your own object id for your own special classes:\n1. Don't! If object_id is broken,\nthen full_dup (and a whole lot of other things too) will also be broken!\n2. It's all on you to do as good a job as Ruby. Like the Ruby object id method,\nyour method must create id values that are unique to each object and are perfectly\nrepeatable for that object.\n3. Really DON'T! I have never found a valid reason for doing so. I doubt that one exists.\n\n## Family Overview\n\nThis gem is a member of a family of four gems that all provide data copying\nservices in a safe, easy to use format. The following outlines the available\ngems and how to chose from among them.\n\nDepth / Action | Need to copy all. | Need to copy data only.\n---------------|------------------------------|------------\nNeed a shallow copy | require 'safe\\_clone' | require 'safe\\_dup'\nNeed a full copy    | require 'full\\_clone' | require 'full\\_dup'\n\n\u003cbr\u003e**Notes**\n* Since none of these gems override the default clone and dup\nmethods, the default behaviors remain available. Further, if multiple,\ndiffering requirements exists, more than one family member gem may be\nemployed in the same project without fear of conflict.\n* If multiple family gems are employed, they will each need to be installed and\nrequired into the application. See below for details.\n* Meta-data attributes include the frozen status and singleton methods. However\nthe tainted status is always copied.\n\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'full_dup'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install full_dup\n\nThe safe_dup gem is at: ( https://rubygems.org/gems/safe_dup )\n\u003cbr\u003eThe safe_clone gem is at: ( https://rubygems.org/gems/safe_clone )\n\u003cbr\u003eThe full_dup gem is at: ( https://rubygems.org/gems/full_dup )\n\u003cbr\u003eThe full_clone gem is at: ( https://rubygems.org/gems/full_clone )\n\n## Usage\n\n    require 'full_dup'\n\nthen, in those places where regular dup was problematic, use:\n\n    foo = my_object.full_dup\n\ninstead of\n\n    foo = my_object.dup\n\nTo exclude some instance variables from the deep duplicating process, define a\nfull_dup_exclude method in the required class:\n\n```ruby\ndef full_dup_exclude\n  [:@bad_var1, :@bad_var2, :@bad_var_etc]\nend\n```\nThis also can be applied to arrays and hashes. In this case, it is possible to\ndefine a singleton method on the duped data. Then the exclude method would\nreturn an array of array indexes or hash keys to be omitted from the full dup\nrecursion. Here is an example that never dupes the first two elements of the\narray:\n\n```ruby\nmy_array.define_singleton_method(:full_dup_exclude) { [0, 1] }\n```\n\u003cbr\u003e**Possible Red Flag** There is a catch here. The dup and full_dup methods\ndo not duplicate singleton methods (unlike the clone and full_clone methods).\nThus any duplicates made in this manner will lose the attached full_dup_exclude\nmethod. If it is important to retain singleton methods, consider using the\nfull_clone gem instead.\n\n### irbt\n\nThe root folder of the full_dup gem contains the file irbt.rb. This program\nopens up the irb repl with the full_dup gem preloaded and is useful for trying\nout the gem interactively.\n\nBy default, irbt will load the system gem version of full dup. The following\ninteractive session demonstrates the difference between dup and full_dup\n\n```\nC:\\Sites\\full_dup\u003eruby irbt.rb\nStarting an IRB console with full_dup loaded.\nfull_dup loaded from gem: 0.0.5\nirb(main):001:0\u003e a = [\"a\", \"b\", \"c\"]\n=\u003e [\"a\", \"b\", \"c\"]\nirb(main):002:0\u003e b = a.dup\n=\u003e [\"a\", \"b\", \"c\"]\nirb(main):003:0\u003e c = a.full_dup\n=\u003e [\"a\", \"b\", \"c\"]\nirb(main):004:0\u003e a[0] \u003c\u003c \"foo\"\n=\u003e \"afoo\"\nirb(main):005:0\u003e a\n=\u003e [\"afoo\", \"b\", \"c\"]\nirb(main):006:0\u003e b\n=\u003e [\"afoo\", \"b\", \"c\"]\nirb(main):007:0\u003e c\n=\u003e [\"a\", \"b\", \"c\"]\nirb(main):008:0\u003e\n```\nTo load the local copy of full_dup use:\n```\n\u003eruby irbt.rb local #optional irb args go here.\n#etc etc etc...\n```\n\n## Contributing\n\n#### Plan A\n\n1. Fork it ( https://github.com/PeterCamilleri/full_dup/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 new Pull Request\n\n#### Plan B\n\nGo to the GitHub repository and raise an issue calling attention to some\naspect that could use some TLC or a suggestion or an idea.\n\n## License\n\nThe gem is available as open source under the terms of the\n[MIT License](./LICENSE.txt).\n\n## Code of Conduct\n\nEveryone interacting in the fully_freeze project’s codebases, issue trackers,\nchat rooms and mailing lists is expected to follow the\n[code of conduct](./CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetercamilleri%2Ffull_dup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpetercamilleri%2Ffull_dup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetercamilleri%2Ffull_dup/lists"}