{"action":"created","comment":{"url":"https://api.github.com/repos/infinitered/redpotion/pulls/comments/29069968","id":29069968,"diff_hunk":"@@ -0,0 +1,187 @@\n+module ProMotion\n+  module DataTable\n+    include ProMotion::Styling\n+    include ProMotion::Table::Utils\n+\n+    def table_view\n+      self.view\n+    end\n+\n+    def screen_setup\n+      set_up_reload_notification\n+      set_up_fetch_controller\n+\n+      # TODO - implement dynamic row height\n+      # set_up_row_height\n+    end\n+\n+    def set_up_reload_notification\n+      NSNotificationCenter.defaultCenter.addObserver(self,\n+        selector: \"update_table_data:\",\n+        name: NSManagedObjectContextDidSaveNotification,\n+        object: nil)\n+    end\n+\n+    def set_up_fetch_controller\n+      error_ptr = Pointer.new(:object)\n+      fetch_controller.delegate = self\n+\n+      unless fetch_controller.performFetch(error_ptr)\n+        raise \"Error performing fetch: #{error_ptr[2].description}\"\n+      end\n+    end\n+\n+    def update_table_data(notification = nil)\n+      data_model.send(:update) if data_model.respond_to?(:update)\n+      Dispatch::Queue.main.async do\n+        fetch_controller.managedObjectContext.mergeChangesFromContextDidSaveNotification(notification)\n+      end\n+    end\n+\n+    # UITableViewDelegate methods\n+    def tableView(table_view, numberOfRowsInSection: section)\n+      fetch_controller.sections[section].numberOfObjects\n+    end\n+\n+    def tableView(table_view, heightForRowAtIndexPath: index_path)\n+      (object_at_index(index_path).cell[:height] || table_view.rowHeight).to_f\n+    end\n+\n+    def tableView(table_view, didSelectRowAtIndexPath: index_path)\n+      data_cell = cell_at(index_path)\n+      table_view.deselectRowAtIndexPath(index_path, animated: true) unless data_cell[:keep_selection] == true\n+      trigger_action(data_cell[:action], data_cell[:arguments], index_path) if data_cell[:action]\n+    end\n+\n+    def tableView(_, cellForRowAtIndexPath: index_path)\n+      params = index_path_to_section_index(index_path: index_path)\n+      data_cell = cell_at(index_path)\n+      return UITableViewCell.alloc.init unless data_cell\n+      create_table_cell(data_cell)\n+    end\n+\n+    def cell_at(index_path)\n+      c = object_at_index(index_path).cell\n+      set_data_cell_defaults c\n+    end\n+\n+    def controllerWillChangeContent(controller)\n+      table_view.beginUpdates\n+    end\n+\n+    def controller(controller, didChangeObject: task, atIndexPath: index_path, forChangeType: change_type, newIndexPath: new_index_path)\n+      case change_type\n+      when NSFetchedResultsChangeInsert\n+        table_view.insertRowsAtIndexPaths([new_index_path], withRowAnimation: UITableViewRowAnimationAutomatic)\n+      when NSFetchedResultsChangeDelete\n+        table_view.deleteRowsAtIndexPaths([index_path], withRowAnimation: UITableViewRowAnimationAutomatic)\n+      when NSFetchedResultsChangeUpdate\n+        table_view.reloadRowsAtIndexPaths([index_path], withRowAnimation: UITableViewRowAnimationAutomatic)\n+      end\n+    end\n+\n+    def controllerDidChangeContent(controller)\n+      table_view.endUpdates\n+    end\n+\n+    def fetch_controller\n+      @_data ||= begin\n+        data_with_scope = data_model.send(data_scope)\n+        if data_with_scope.sort_descriptors.empty?\n+          # Try to be smart about how we sort things if a sort descriptor doesn't exist\n+          attributes = data_model.send(:attribute_names)\n+          sort_attribute = nil\n+          [:updated_at, :created_at, :id].each do |att|\n+            sort_attribute ||= att if attributes.include?(att.to_s)\n+          end\n+\n+          if sort_attribute\n+            PM.logger.warn(\"The `#{data_model}` model scope `#{data_scope}` needs a sort descriptor. Add sort_by(:property) to your scope. Currently sorting by :#{sort_attribute}.\")\n+            data_model.send(data_scope).sort_by(sort_attribute)\n+          else\n+            # This is where the application says goodbye and dies in a fiery crash.\n+            PM.logger.error(\"The `#{data_model}` model scope `#{data_scope}` needs a sort descriptor. Add sort_by(:property) to your scope.\")\n+          end\n+        else\n+          data_with_scope\n+        end\n+      end\n+\n+      @fetch_controller ||= NSFetchedResultsController.alloc.initWithFetchRequest(\n+        @_data.fetch_request,\n+        managedObjectContext: @_data.context,\n+        sectionNameKeyPath: nil,","path":"lib/project/pro_motion/data_table.rb","position":113,"original_position":113,"commit_id":"d1ae57e95c4b9f788249d8408606670f9e346dab","original_commit_id":"d1ae57e95c4b9f788249d8408606670f9e346dab","user":{"login":"markrickert","id":139261,"avatar_url":"https://avatars.githubusercontent.com/u/139261?v=3","gravatar_id":"","url":"https://api.github.com/users/markrickert","html_url":"https://github.com/markrickert","followers_url":"https://api.github.com/users/markrickert/followers","following_url":"https://api.github.com/users/markrickert/following{/other_user}","gists_url":"https://api.github.com/users/markrickert/gists{/gist_id}","starred_url":"https://api.github.com/users/markrickert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markrickert/subscriptions","organizations_url":"https://api.github.com/users/markrickert/orgs","repos_url":"https://api.github.com/users/markrickert/repos","events_url":"https://api.github.com/users/markrickert/events{/privacy}","received_events_url":"https://api.github.com/users/markrickert/received_events","type":"User","site_admin":false},"body":"The context should come from the core data fetch request generated by the scope above. ","created_at":"2015-04-24T17:51:17Z","updated_at":"2015-04-24T17:51:17Z","html_url":"https://github.com/infinitered/redpotion/pull/86#discussion_r29069968","pull_request_url":"https://api.github.com/repos/infinitered/redpotion/pulls/86","_links":{"self":{"href":"https://api.github.com/repos/infinitered/redpotion/pulls/comments/29069968"},"html":{"href":"https://github.com/infinitered/redpotion/pull/86#discussion_r29069968"},"pull_request":{"href":"https://api.github.com/repos/infinitered/redpotion/pulls/86"}}},"pull_request":{"url":"https://api.github.com/repos/infinitered/redpotion/pulls/86","id":34010405,"html_url":"https://github.com/infinitered/redpotion/pull/86","diff_url":"https://github.com/infinitered/redpotion/pull/86.diff","patch_url":"https://github.com/infinitered/redpotion/pull/86.patch","issue_url":"https://api.github.com/repos/infinitered/redpotion/issues/86","number":86,"state":"open","locked":false,"title":"Woah! DataTableScreens now use a proper fetch controller!","user":{"login":"markrickert","id":139261,"avatar_url":"https://avatars.githubusercontent.com/u/139261?v=3","gravatar_id":"","url":"https://api.github.com/users/markrickert","html_url":"https://github.com/markrickert","followers_url":"https://api.github.com/users/markrickert/followers","following_url":"https://api.github.com/users/markrickert/following{/other_user}","gists_url":"https://api.github.com/users/markrickert/gists{/gist_id}","starred_url":"https://api.github.com/users/markrickert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markrickert/subscriptions","organizations_url":"https://api.github.com/users/markrickert/orgs","repos_url":"https://api.github.com/users/markrickert/repos","events_url":"https://api.github.com/users/markrickert/events{/privacy}","received_events_url":"https://api.github.com/users/markrickert/received_events","type":"User","site_admin":false},"body":"This gives us all sorts of awesome functionality like automatically updating the table when the core data changes.\r\n\r\nIt's *magic*!\r\n\r\n![MAGIC](http://i.imgur.com/1SHAumY.gif \"Magic!\")\r\n\r\nThis supersedes #81\r\n\r\nThings to do:\r\n\r\n- [ ] ProMotion: move [`TableClassMethods`](https://github.com/clearsightstudio/ProMotion/blob/173b412e48e74d37c9e7b86f2abae703f5bdea25/lib/ProMotion/table/table.rb#L350-L427) to its own file so we can reuse it here.\r\n- [ ] ProMotion: extract the following methods from [`PM::TableData`](https://github.com/clearsightstudio/ProMotion/blob/173b412e48e74d37c9e7b86f2abae703f5bdea25/lib/ProMotion/table/data/table_data.rb): `create_table_cell`, `set_data_cell_defaults`, `build_cell_identifier`","created_at":"2015-04-24T00:45:06Z","updated_at":"2015-04-24T17:51:17Z","closed_at":null,"merged_at":null,"merge_commit_sha":"23d2cde4e1182497ce881df9d9924104ef565e2b","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/infinitered/redpotion/pulls/86/commits","review_comments_url":"https://api.github.com/repos/infinitered/redpotion/pulls/86/comments","review_comment_url":"https://api.github.com/repos/infinitered/redpotion/pulls/comments{/number}","comments_url":"https://api.github.com/repos/infinitered/redpotion/issues/86/comments","statuses_url":"https://api.github.com/repos/infinitered/redpotion/statuses/d1ae57e95c4b9f788249d8408606670f9e346dab","head":{"label":"infinitered:data-table-screen_fetched_results_controller","ref":"data-table-screen_fetched_results_controller","sha":"d1ae57e95c4b9f788249d8408606670f9e346dab","user":{"login":"infinitered","id":3902527,"avatar_url":"https://avatars.githubusercontent.com/u/3902527?v=3","gravatar_id":"","url":"https://api.github.com/users/infinitered","html_url":"https://github.com/infinitered","followers_url":"https://api.github.com/users/infinitered/followers","following_url":"https://api.github.com/users/infinitered/following{/other_user}","gists_url":"https://api.github.com/users/infinitered/gists{/gist_id}","starred_url":"https://api.github.com/users/infinitered/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/infinitered/subscriptions","organizations_url":"https://api.github.com/users/infinitered/orgs","repos_url":"https://api.github.com/users/infinitered/repos","events_url":"https://api.github.com/users/infinitered/events{/privacy}","received_events_url":"https://api.github.com/users/infinitered/received_events","type":"Organization","site_admin":false},"repo":{"id":26648250,"name":"redpotion","full_name":"infinitered/redpotion","owner":{"login":"infinitered","id":3902527,"avatar_url":"https://avatars.githubusercontent.com/u/3902527?v=3","gravatar_id":"","url":"https://api.github.com/users/infinitered","html_url":"https://github.com/infinitered","followers_url":"https://api.github.com/users/infinitered/followers","following_url":"https://api.github.com/users/infinitered/following{/other_user}","gists_url":"https://api.github.com/users/infinitered/gists{/gist_id}","starred_url":"https://api.github.com/users/infinitered/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/infinitered/subscriptions","organizations_url":"https://api.github.com/users/infinitered/orgs","repos_url":"https://api.github.com/users/infinitered/repos","events_url":"https://api.github.com/users/infinitered/events{/privacy}","received_events_url":"https://api.github.com/users/infinitered/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/infinitered/redpotion","description":"We believe iPhone development should be clean, scalable, and fast with a language that developers not only enjoy, but actively choose. With the advent of Ruby for iPhone development the RubyMotion community has combined and tested the most active and powerful gems into a single package called RedPotion","fork":false,"url":"https://api.github.com/repos/infinitered/redpotion","forks_url":"https://api.github.com/repos/infinitered/redpotion/forks","keys_url":"https://api.github.com/repos/infinitered/redpotion/keys{/key_id}","collaborators_url":"https://api.github.com/repos/infinitered/redpotion/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/infinitered/redpotion/teams","hooks_url":"https://api.github.com/repos/infinitered/redpotion/hooks","issue_events_url":"https://api.github.com/repos/infinitered/redpotion/issues/events{/number}","events_url":"https://api.github.com/repos/infinitered/redpotion/events","assignees_url":"https://api.github.com/repos/infinitered/redpotion/assignees{/user}","branches_url":"https://api.github.com/repos/infinitered/redpotion/branches{/branch}","tags_url":"https://api.github.com/repos/infinitered/redpotion/tags","blobs_url":"https://api.github.com/repos/infinitered/redpotion/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/infinitered/redpotion/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/infinitered/redpotion/git/refs{/sha}","trees_url":"https://api.github.com/repos/infinitered/redpotion/git/trees{/sha}","statuses_url":"https://api.github.com/repos/infinitered/redpotion/statuses/{sha}","languages_url":"https://api.github.com/repos/infinitered/redpotion/languages","stargazers_url":"https://api.github.com/repos/infinitered/redpotion/stargazers","contributors_url":"https://api.github.com/repos/infinitered/redpotion/contributors","subscribers_url":"https://api.github.com/repos/infinitered/redpotion/subscribers","subscription_url":"https://api.github.com/repos/infinitered/redpotion/subscription","commits_url":"https://api.github.com/repos/infinitered/redpotion/commits{/sha}","git_commits_url":"https://api.github.com/repos/infinitered/redpotion/git/commits{/sha}","comments_url":"https://api.github.com/repos/infinitered/redpotion/comments{/number}","issue_comment_url":"https://api.github.com/repos/infinitered/redpotion/issues/comments{/number}","contents_url":"https://api.github.com/repos/infinitered/redpotion/contents/{+path}","compare_url":"https://api.github.com/repos/infinitered/redpotion/compare/{base}...{head}","merges_url":"https://api.github.com/repos/infinitered/redpotion/merges","archive_url":"https://api.github.com/repos/infinitered/redpotion/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/infinitered/redpotion/downloads","issues_url":"https://api.github.com/repos/infinitered/redpotion/issues{/number}","pulls_url":"https://api.github.com/repos/infinitered/redpotion/pulls{/number}","milestones_url":"https://api.github.com/repos/infinitered/redpotion/milestones{/number}","notifications_url":"https://api.github.com/repos/infinitered/redpotion/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/infinitered/redpotion/labels{/name}","releases_url":"https://api.github.com/repos/infinitered/redpotion/releases{/id}","created_at":"2014-11-14T16:56:07Z","updated_at":"2015-04-24T12:54:17Z","pushed_at":"2015-04-24T05:15:35Z","git_url":"git://github.com/infinitered/redpotion.git","ssh_url":"git@github.com:infinitered/redpotion.git","clone_url":"https://github.com/infinitered/redpotion.git","svn_url":"https://github.com/infinitered/redpotion","homepage":"","size":1906,"stargazers_count":79,"watchers_count":79,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":15,"mirror_url":null,"open_issues_count":10,"forks":15,"open_issues":10,"watchers":79,"default_branch":"master"}},"base":{"label":"infinitered:master","ref":"master","sha":"b6c55d135bb141792e641deb41ebdac7908156fe","user":{"login":"infinitered","id":3902527,"avatar_url":"https://avatars.githubusercontent.com/u/3902527?v=3","gravatar_id":"","url":"https://api.github.com/users/infinitered","html_url":"https://github.com/infinitered","followers_url":"https://api.github.com/users/infinitered/followers","following_url":"https://api.github.com/users/infinitered/following{/other_user}","gists_url":"https://api.github.com/users/infinitered/gists{/gist_id}","starred_url":"https://api.github.com/users/infinitered/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/infinitered/subscriptions","organizations_url":"https://api.github.com/users/infinitered/orgs","repos_url":"https://api.github.com/users/infinitered/repos","events_url":"https://api.github.com/users/infinitered/events{/privacy}","received_events_url":"https://api.github.com/users/infinitered/received_events","type":"Organization","site_admin":false},"repo":{"id":26648250,"name":"redpotion","full_name":"infinitered/redpotion","owner":{"login":"infinitered","id":3902527,"avatar_url":"https://avatars.githubusercontent.com/u/3902527?v=3","gravatar_id":"","url":"https://api.github.com/users/infinitered","html_url":"https://github.com/infinitered","followers_url":"https://api.github.com/users/infinitered/followers","following_url":"https://api.github.com/users/infinitered/following{/other_user}","gists_url":"https://api.github.com/users/infinitered/gists{/gist_id}","starred_url":"https://api.github.com/users/infinitered/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/infinitered/subscriptions","organizations_url":"https://api.github.com/users/infinitered/orgs","repos_url":"https://api.github.com/users/infinitered/repos","events_url":"https://api.github.com/users/infinitered/events{/privacy}","received_events_url":"https://api.github.com/users/infinitered/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/infinitered/redpotion","description":"We believe iPhone development should be clean, scalable, and fast with a language that developers not only enjoy, but actively choose. With the advent of Ruby for iPhone development the RubyMotion community has combined and tested the most active and powerful gems into a single package called RedPotion","fork":false,"url":"https://api.github.com/repos/infinitered/redpotion","forks_url":"https://api.github.com/repos/infinitered/redpotion/forks","keys_url":"https://api.github.com/repos/infinitered/redpotion/keys{/key_id}","collaborators_url":"https://api.github.com/repos/infinitered/redpotion/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/infinitered/redpotion/teams","hooks_url":"https://api.github.com/repos/infinitered/redpotion/hooks","issue_events_url":"https://api.github.com/repos/infinitered/redpotion/issues/events{/number}","events_url":"https://api.github.com/repos/infinitered/redpotion/events","assignees_url":"https://api.github.com/repos/infinitered/redpotion/assignees{/user}","branches_url":"https://api.github.com/repos/infinitered/redpotion/branches{/branch}","tags_url":"https://api.github.com/repos/infinitered/redpotion/tags","blobs_url":"https://api.github.com/repos/infinitered/redpotion/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/infinitered/redpotion/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/infinitered/redpotion/git/refs{/sha}","trees_url":"https://api.github.com/repos/infinitered/redpotion/git/trees{/sha}","statuses_url":"https://api.github.com/repos/infinitered/redpotion/statuses/{sha}","languages_url":"https://api.github.com/repos/infinitered/redpotion/languages","stargazers_url":"https://api.github.com/repos/infinitered/redpotion/stargazers","contributors_url":"https://api.github.com/repos/infinitered/redpotion/contributors","subscribers_url":"https://api.github.com/repos/infinitered/redpotion/subscribers","subscription_url":"https://api.github.com/repos/infinitered/redpotion/subscription","commits_url":"https://api.github.com/repos/infinitered/redpotion/commits{/sha}","git_commits_url":"https://api.github.com/repos/infinitered/redpotion/git/commits{/sha}","comments_url":"https://api.github.com/repos/infinitered/redpotion/comments{/number}","issue_comment_url":"https://api.github.com/repos/infinitered/redpotion/issues/comments{/number}","contents_url":"https://api.github.com/repos/infinitered/redpotion/contents/{+path}","compare_url":"https://api.github.com/repos/infinitered/redpotion/compare/{base}...{head}","merges_url":"https://api.github.com/repos/infinitered/redpotion/merges","archive_url":"https://api.github.com/repos/infinitered/redpotion/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/infinitered/redpotion/downloads","issues_url":"https://api.github.com/repos/infinitered/redpotion/issues{/number}","pulls_url":"https://api.github.com/repos/infinitered/redpotion/pulls{/number}","milestones_url":"https://api.github.com/repos/infinitered/redpotion/milestones{/number}","notifications_url":"https://api.github.com/repos/infinitered/redpotion/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/infinitered/redpotion/labels{/name}","releases_url":"https://api.github.com/repos/infinitered/redpotion/releases{/id}","created_at":"2014-11-14T16:56:07Z","updated_at":"2015-04-24T12:54:17Z","pushed_at":"2015-04-24T05:15:35Z","git_url":"git://github.com/infinitered/redpotion.git","ssh_url":"git@github.com:infinitered/redpotion.git","clone_url":"https://github.com/infinitered/redpotion.git","svn_url":"https://github.com/infinitered/redpotion","homepage":"","size":1906,"stargazers_count":79,"watchers_count":79,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":15,"mirror_url":null,"open_issues_count":10,"forks":15,"open_issues":10,"watchers":79,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/infinitered/redpotion/pulls/86"},"html":{"href":"https://github.com/infinitered/redpotion/pull/86"},"issue":{"href":"https://api.github.com/repos/infinitered/redpotion/issues/86"},"comments":{"href":"https://api.github.com/repos/infinitered/redpotion/issues/86/comments"},"review_comments":{"href":"https://api.github.com/repos/infinitered/redpotion/pulls/86/comments"},"review_comment":{"href":"https://api.github.com/repos/infinitered/redpotion/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/infinitered/redpotion/pulls/86/commits"},"statuses":{"href":"https://api.github.com/repos/infinitered/redpotion/statuses/d1ae57e95c4b9f788249d8408606670f9e346dab"}}}}