{"id":15405588,"url":"https://github.com/krisleech/wisper-attributes","last_synced_at":"2025-10-15T14:32:08.841Z","repository":{"id":17107119,"uuid":"19872853","full_name":"krisleech/wisper-attributes","owner":"krisleech","description":"Transparently publish attribute changes to subscribers","archived":false,"fork":false,"pushed_at":"2014-05-16T22:42:30.000Z","size":108,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-07T13:45:35.963Z","etag":null,"topics":[],"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/krisleech.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":"2014-05-16T22:42:14.000Z","updated_at":"2019-08-13T15:41:49.000Z","dependencies_parsed_at":"2022-08-04T16:30:45.728Z","dependency_job_id":null,"html_url":"https://github.com/krisleech/wisper-attributes","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/krisleech/wisper-attributes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krisleech%2Fwisper-attributes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krisleech%2Fwisper-attributes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krisleech%2Fwisper-attributes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krisleech%2Fwisper-attributes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/krisleech","download_url":"https://codeload.github.com/krisleech/wisper-attributes/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krisleech%2Fwisper-attributes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279085462,"owners_count":26100017,"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-10-15T02:00:07.814Z","response_time":56,"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":[],"created_at":"2024-10-01T16:17:21.611Z","updated_at":"2025-10-15T14:32:08.790Z","avatar_url":"https://github.com/krisleech.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Wisper::Attributes [WIP]\n\nAttributes are declared as usual, any changes result in an event being\nbroadcast with details of the changes.\n\nAn example use case would be to audit all changes to instances of particular\ntypes, might be useful as a poor persons profiler.\n\n## Installation\n\n```ruby\ngem 'wisper-attributes'\n```\n\n## Usage\n\n**Starting with a regular class**\n\n```ruby\nclass CoffeeMaker\n  include Wisper::Attributes\n\n  attr_accessor :name\nend\n```\n\n**An example listener which will record changes in memory**\n\n```ruby\nclass Auditor\n  include Singleton\n\n  attr_accessor :changes\n\n  def initialize\n    @changes ||= []\n  end\n\n  def on_changed(subject, attribute, changes)\n    changes.push(subject_id: subject.id,\n                 subject_class: subject.class.to_s,\n                 attribute: attribute,\n                 from: changes[:from],\n                 to: changes[:to])\n  end\n\n  def self.changes\n    instance.changes\n  end\nend\n```\n\n**For demo purposes we globally subscribe the listener**\n\n```ruby\nWisper.add_listener(Auditor.new)\n```\n\n**Make some changes**\n\n```ruby\ncoffee_maker = CoffeeMaker.new\ncoffee_maker.name = ‘Happy Days’\n```\n\n**And see that the changes that have been recorded**\n\n```ruby\nAuditor.changes # =\u003e [..]\n```\n\n## Contributing\n\nPlease submit a Pull Request with specs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrisleech%2Fwisper-attributes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkrisleech%2Fwisper-attributes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrisleech%2Fwisper-attributes/lists"}