{"action":"created","issue":{"url":"https://api.github.com/repos/jdickey/new_poc/issues/247","labels_url":"https://api.github.com/repos/jdickey/new_poc/issues/247/labels{/name}","comments_url":"https://api.github.com/repos/jdickey/new_poc/issues/247/comments","events_url":"https://api.github.com/repos/jdickey/new_poc/issues/247/events","html_url":"https://github.com/jdickey/new_poc/pull/247","id":60639375,"number":247,"title":"Beginning reimplementation of User entity.","user":{"login":"jdickey","id":157938,"avatar_url":"https://avatars.githubusercontent.com/u/157938?v=3","gravatar_id":"","url":"https://api.github.com/users/jdickey","html_url":"https://github.com/jdickey","followers_url":"https://api.github.com/users/jdickey/followers","following_url":"https://api.github.com/users/jdickey/following{/other_user}","gists_url":"https://api.github.com/users/jdickey/gists{/gist_id}","starred_url":"https://api.github.com/users/jdickey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jdickey/subscriptions","organizations_url":"https://api.github.com/users/jdickey/orgs","repos_url":"https://api.github.com/users/jdickey/repos","events_url":"https://api.github.com/users/jdickey/events{/privacy}","received_events_url":"https://api.github.com/users/jdickey/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/jdickey/new_poc/labels/in%20progress","name":"in progress","color":"ededed"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":6,"created_at":"2015-03-11T10:41:09Z","updated_at":"2015-03-15T18:35:21Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/jdickey/new_poc/pulls/247","html_url":"https://github.com/jdickey/new_poc/pull/247","diff_url":"https://github.com/jdickey/new_poc/pull/247.diff","patch_url":"https://github.com/jdickey/new_poc/pull/247.patch"},"body":"Per Issue #54 and Issue #240, pulling back from  \"unbuilt Gem\" into main app, applying lessons learnt\r\nalong the way.\r\n"},"comment":{"url":"https://api.github.com/repos/jdickey/new_poc/issues/comments/81192543","html_url":"https://github.com/jdickey/new_poc/pull/247#issuecomment-81192543","issue_url":"https://api.github.com/repos/jdickey/new_poc/issues/247","id":81192543,"user":{"login":"jdickey","id":157938,"avatar_url":"https://avatars.githubusercontent.com/u/157938?v=3","gravatar_id":"","url":"https://api.github.com/users/jdickey","html_url":"https://github.com/jdickey","followers_url":"https://api.github.com/users/jdickey/followers","following_url":"https://api.github.com/users/jdickey/following{/other_user}","gists_url":"https://api.github.com/users/jdickey/gists{/gist_id}","starred_url":"https://api.github.com/users/jdickey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jdickey/subscriptions","organizations_url":"https://api.github.com/users/jdickey/orgs","repos_url":"https://api.github.com/users/jdickey/repos","events_url":"https://api.github.com/users/jdickey/events{/privacy}","received_events_url":"https://api.github.com/users/jdickey/received_events","type":"User","site_admin":false},"created_at":"2015-03-15T18:35:20Z","updated_at":"2015-03-15T18:35:20Z","body":"The \"obvious quick fix\" to this would be simply to replace the existing [`#attributes`](https://github.com/jdickey/new_poc/blob/d0ca00b/app/entities/user/core_attribute_setup/internals.rb#L25-L27) implementation with one that explicitly builds a `Hash` (or equivalent) with explicit items, either by selectively white- or blacklisting `instance_values` entries.\r\n\r\nIs that *good enough* and *fast enough* to overcome the new SRP violation? Or is there a better way, sufficiently easy/quick to be practical while at the same time not duplicating or replacing the work that has gone (recently) before?\r\n\r\nSure there is, and it's clued in by the fact that every single attribute that we want to treat *as* an attribute has the equivalent of the code `entity.class_eval { attr_reader :the_attribute }`. Attributes, instead of making that call, should instead call a (new) method we mix in to the entity, tentatively named `#add_attribute`. Here's what it might look like:\r\n\r\n```ruby\r\n        entity.define_singleton_method :add_attribute do |attribute, value|\r\n          class_eval { attr_reader attribute }\r\n          instance_variable_set \"@#{attribute}\".to_sym, value\r\n          @attribute_keys ||= []\r\n          @attribute_keys.push attribute\r\n          self\r\n        end\r\n```\r\n\r\nThus, methods such as [`PersistenceSetup.setup`] that presently include the code\r\n\r\n```ruby\r\n        entity.instance_variable_set :@slug, attributes[:slug]\r\n        entity.class_eval { attr_reader :slug }\r\n```\r\n\r\nwould replace that with the single line `entity.add_attribute :slug, attributes[:slug]` and be done with that.\r\n\r\nThe [definition of the `#attributes` method](https://github.com/jdickey/new_poc/blob/d0ca00b/app/entities/user/core_attribute_setup/internals.rb#L25-L27) would then be replaced by the following:\r\n\r\n```ruby\r\n          entity.define_singleton_method :attributes do\r\n            {}.tap do |ret|\r\n              @attribute_keys.each do |key|\r\n                ret[key] = instance_variable_get \"@#{key}\".to_sym\r\n              end\r\n            end\r\n          end\r\n```\r\n\r\nThoughts?"}}