{"action":"created","comment":{"url":"https://api.github.com/repos/guard/guard/pulls/comments/122573144","pull_request_review_id":44704533,"id":122573144,"diff_hunk":"@@ -0,0 +1,279 @@\n+require \"guard\"\n+require \"guard/internals/groups\"\n+\n+module Guard\n+  module API\n+    TEMPLATE_FORMAT = \"%s/lib/guard/%s/templates/Guardfile\"\n+\n+    require \"guard/ui\"\n+\n+    def self.included(base)\n+      base.extend(ClassMethods)\n+      base.class_eval do\n+        attr_accessor :group, :watchers, :callbacks, :options\n+      end\n+    end\n+\n+    module ClassMethods\n+      # Get all callbacks registered for all Guard plugins present in the\n+      # Guardfile.\n+      #\n+      def callbacks\n+        @callbacks ||= Hash.new { |hash, key| hash[key] = [] }\n+      end\n+\n+      # Add a callback.\n+      #\n+      # @param [Block] listener the listener to notify\n+      # @param [Guard::Plugin] guard_plugin the Guard plugin to add the callback\n+      # @param [Array<Symbol>] events the events to register\n+      #\n+      def add_callback(listener, guard_plugin, events)\n+        Array(events).each do |event|\n+          callbacks[[guard_plugin, event]] << listener\n+        end\n+      end\n+\n+      # Notify a callback.\n+      #\n+      # @param [Guard::Plugin] guard_plugin the Guard plugin to add the callback\n+      # @param [Symbol] event the event to trigger\n+      # @param [Array] args the arguments for the listener\n+      #\n+      def notify(guard_plugin, event, *args)\n+        callbacks[[guard_plugin, event]].each do |listener|\n+          listener.call(guard_plugin, event, *args)\n+        end\n+      end\n+\n+      # Reset all callbacks.\n+      #\n+      # TODO: remove (not used anywhere)\n+      def reset_callbacks!\n+        @callbacks = nil\n+      end\n+\n+      # Returns the non-namespaced class name of the plugin\n+      #\n+      #\n+      # @example Non-namespaced class name for Guard::RSpec\n+      #   Guard::RSpec.non_namespaced_classname\n+      #   #=> \"RSpec\"\n+      #\n+      # @return [String]\n+      #\n+      def non_namespaced_classname\n+        to_s.sub(\"Guard::\", \"\")\n+      end\n+\n+      # Returns the non-namespaced name of the plugin\n+      #\n+      #\n+      # @example Non-namespaced name for Guard::RSpec\n+      #   Guard::RSpec.non_namespaced_name\n+      #   #=> \"rspec\"\n+      #\n+      # @return [String]\n+      #\n+      def non_namespaced_name\n+        non_namespaced_classname.downcase\n+      end\n+\n+      # Specify the source for the Guardfile template.\n+      # Each Guard plugin can redefine this method to add its own logic.\n+      #\n+      # @param [String] plugin_location the plugin location\n+      #\n+      def template(plugin_location)\n+        File.read(format(TEMPLATE_FORMAT, plugin_location, non_namespaced_name))\n+      end\n+    end\n+\n+    # When event is a Symbol, {#hook} will generate a hook name\n+    # by concatenating the method name from where {#hook} is called\n+    # with the given Symbol.\n+    #\n+    # @example Add a hook with a Symbol\n+    #\n+    #   def run_all\n+    #     hook :foo\n+    #   end\n+    #\n+    # Here, when {Guard::Plugin#run_all} is called, {#hook} will notify\n+    # callbacks registered for the \"run_all_foo\" event.\n+    #\n+    # When event is a String, {#hook} will directly turn the String\n+    # into a Symbol.\n+    #\n+    # @example Add a hook with a String\n+    #\n+    #   def run_all\n+    #     hook \"foo_bar\"\n+    #   end\n+    #\n+    # When {Guard::Plugin::run_all} is called, {#hook} will notify\n+    # callbacks registered for the \"foo_bar\" event.\n+    #\n+    # @param [Symbol, String] event the name of the Guard event\n+    # @param [Array] args the parameters are passed as is to the callbacks\n+    #   registered for the given event.\n+    #\n+    def hook(event, *args)\n+      hook_name = if event.is_a? Symbol\n+                    calling_method = caller[0][/`([^']*)'/, 1]\n+                    \"#{ calling_method }_#{ event }\"\n+                  else\n+                    event\n+                  end\n+\n+      UI.debug \"Hook :#{ hook_name } executed for #{ self.class }\"\n+\n+      self.class.notify(self, hook_name.to_sym, *args)\n+    end\n+\n+    # Called once when Guard starts. Please override initialize method to\n+    # init stuff.\n+    #\n+    # @raise [:task_has_failed] when start has failed\n+    # @return [Object] the task result\n+    #\n+    def start","path":"lib/guard/api.rb","position":140,"original_position":140,"commit_id":"80c385bf9a2b1d44a96057f62c84dd250411cd22","original_commit_id":"80c385bf9a2b1d44a96057f62c84dd250411cd22","user":{"login":"houndci-bot","id":6697940,"avatar_url":"https://avatars3.githubusercontent.com/u/6697940?v=3","gravatar_id":"","url":"https://api.github.com/users/houndci-bot","html_url":"https://github.com/houndci-bot","followers_url":"https://api.github.com/users/houndci-bot/followers","following_url":"https://api.github.com/users/houndci-bot/following{/other_user}","gists_url":"https://api.github.com/users/houndci-bot/gists{/gist_id}","starred_url":"https://api.github.com/users/houndci-bot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/houndci-bot/subscriptions","organizations_url":"https://api.github.com/users/houndci-bot/orgs","repos_url":"https://api.github.com/users/houndci-bot/repos","events_url":"https://api.github.com/users/houndci-bot/events{/privacy}","received_events_url":"https://api.github.com/users/houndci-bot/received_events","type":"User","site_admin":false},"body":"Put empty method definitions on a single line.","created_at":"2017-06-17T17:28:20Z","updated_at":"2017-06-17T17:28:21Z","html_url":"https://github.com/guard/guard/pull/873#discussion_r122573144","pull_request_url":"https://api.github.com/repos/guard/guard/pulls/873","_links":{"self":{"href":"https://api.github.com/repos/guard/guard/pulls/comments/122573144"},"html":{"href":"https://github.com/guard/guard/pull/873#discussion_r122573144"},"pull_request":{"href":"https://api.github.com/repos/guard/guard/pulls/873"}}},"pull_request":{"url":"https://api.github.com/repos/guard/guard/pulls/873","id":126162118,"html_url":"https://github.com/guard/guard/pull/873","diff_url":"https://github.com/guard/guard/pull/873.diff","patch_url":"https://github.com/guard/guard/pull/873.patch","issue_url":"https://api.github.com/repos/guard/guard/issues/873","number":873,"state":"open","locked":false,"title":"[RFC] Add a Guard::API module that Guard plugins should include","user":{"login":"rymai","id":1168,"avatar_url":"https://avatars0.githubusercontent.com/u/1168?v=3","gravatar_id":"","url":"https://api.github.com/users/rymai","html_url":"https://github.com/rymai","followers_url":"https://api.github.com/users/rymai/followers","following_url":"https://api.github.com/users/rymai/following{/other_user}","gists_url":"https://api.github.com/users/rymai/gists{/gist_id}","starred_url":"https://api.github.com/users/rymai/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rymai/subscriptions","organizations_url":"https://api.github.com/users/rymai/orgs","repos_url":"https://api.github.com/users/rymai/repos","events_url":"https://api.github.com/users/rymai/events{/privacy}","received_events_url":"https://api.github.com/users/rymai/received_events","type":"User","site_admin":false},"body":"This is a first step toward a sanitized plugin architecture: Mixin instead of inheritance.\r\n\r\n@ioquatix @e2 @thibaudgg What do you think?\r\n\r\nRelated to #691 and https://github.com/guard/guard/issues/713#issuecomment-308895364.","created_at":"2017-06-17T17:28:08Z","updated_at":"2017-06-17T17:28:21Z","closed_at":null,"merged_at":null,"merge_commit_sha":"273e1e9b6c37441febe9d12caf862e441265ee5d","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/guard/guard/pulls/873/commits","review_comments_url":"https://api.github.com/repos/guard/guard/pulls/873/comments","review_comment_url":"https://api.github.com/repos/guard/guard/pulls/comments{/number}","comments_url":"https://api.github.com/repos/guard/guard/issues/873/comments","statuses_url":"https://api.github.com/repos/guard/guard/statuses/80c385bf9a2b1d44a96057f62c84dd250411cd22","head":{"label":"guard:guard-api","ref":"guard-api","sha":"80c385bf9a2b1d44a96057f62c84dd250411cd22","user":{"login":"guard","id":351846,"avatar_url":"https://avatars3.githubusercontent.com/u/351846?v=3","gravatar_id":"","url":"https://api.github.com/users/guard","html_url":"https://github.com/guard","followers_url":"https://api.github.com/users/guard/followers","following_url":"https://api.github.com/users/guard/following{/other_user}","gists_url":"https://api.github.com/users/guard/gists{/gist_id}","starred_url":"https://api.github.com/users/guard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guard/subscriptions","organizations_url":"https://api.github.com/users/guard/orgs","repos_url":"https://api.github.com/users/guard/repos","events_url":"https://api.github.com/users/guard/events{/privacy}","received_events_url":"https://api.github.com/users/guard/received_events","type":"Organization","site_admin":false},"repo":{"id":812610,"name":"guard","full_name":"guard/guard","owner":{"login":"guard","id":351846,"avatar_url":"https://avatars3.githubusercontent.com/u/351846?v=3","gravatar_id":"","url":"https://api.github.com/users/guard","html_url":"https://github.com/guard","followers_url":"https://api.github.com/users/guard/followers","following_url":"https://api.github.com/users/guard/following{/other_user}","gists_url":"https://api.github.com/users/guard/gists{/gist_id}","starred_url":"https://api.github.com/users/guard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guard/subscriptions","organizations_url":"https://api.github.com/users/guard/orgs","repos_url":"https://api.github.com/users/guard/repos","events_url":"https://api.github.com/users/guard/events{/privacy}","received_events_url":"https://api.github.com/users/guard/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/guard/guard","description":"Guard is a command line tool to easily handle events on file system modifications.","fork":false,"url":"https://api.github.com/repos/guard/guard","forks_url":"https://api.github.com/repos/guard/guard/forks","keys_url":"https://api.github.com/repos/guard/guard/keys{/key_id}","collaborators_url":"https://api.github.com/repos/guard/guard/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/guard/guard/teams","hooks_url":"https://api.github.com/repos/guard/guard/hooks","issue_events_url":"https://api.github.com/repos/guard/guard/issues/events{/number}","events_url":"https://api.github.com/repos/guard/guard/events","assignees_url":"https://api.github.com/repos/guard/guard/assignees{/user}","branches_url":"https://api.github.com/repos/guard/guard/branches{/branch}","tags_url":"https://api.github.com/repos/guard/guard/tags","blobs_url":"https://api.github.com/repos/guard/guard/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/guard/guard/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/guard/guard/git/refs{/sha}","trees_url":"https://api.github.com/repos/guard/guard/git/trees{/sha}","statuses_url":"https://api.github.com/repos/guard/guard/statuses/{sha}","languages_url":"https://api.github.com/repos/guard/guard/languages","stargazers_url":"https://api.github.com/repos/guard/guard/stargazers","contributors_url":"https://api.github.com/repos/guard/guard/contributors","subscribers_url":"https://api.github.com/repos/guard/guard/subscribers","subscription_url":"https://api.github.com/repos/guard/guard/subscription","commits_url":"https://api.github.com/repos/guard/guard/commits{/sha}","git_commits_url":"https://api.github.com/repos/guard/guard/git/commits{/sha}","comments_url":"https://api.github.com/repos/guard/guard/comments{/number}","issue_comment_url":"https://api.github.com/repos/guard/guard/issues/comments{/number}","contents_url":"https://api.github.com/repos/guard/guard/contents/{+path}","compare_url":"https://api.github.com/repos/guard/guard/compare/{base}...{head}","merges_url":"https://api.github.com/repos/guard/guard/merges","archive_url":"https://api.github.com/repos/guard/guard/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/guard/guard/downloads","issues_url":"https://api.github.com/repos/guard/guard/issues{/number}","pulls_url":"https://api.github.com/repos/guard/guard/pulls{/number}","milestones_url":"https://api.github.com/repos/guard/guard/milestones{/number}","notifications_url":"https://api.github.com/repos/guard/guard/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/guard/guard/labels{/name}","releases_url":"https://api.github.com/repos/guard/guard/releases{/id}","deployments_url":"https://api.github.com/repos/guard/guard/deployments","created_at":"2010-08-02T16:26:44Z","updated_at":"2017-06-15T17:50:47Z","pushed_at":"2017-06-17T17:28:08Z","git_url":"git://github.com/guard/guard.git","ssh_url":"git@github.com:guard/guard.git","clone_url":"https://github.com/guard/guard.git","svn_url":"https://github.com/guard/guard","homepage":"http://guardgem.org","size":3742,"stargazers_count":5363,"watchers_count":5363,"language":"Ruby","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":462,"mirror_url":null,"open_issues_count":45,"forks":462,"open_issues":45,"watchers":5363,"default_branch":"master"}},"base":{"label":"guard:master","ref":"master","sha":"02701711ddfabfbf38dfc9a147d5d3940a03bb5b","user":{"login":"guard","id":351846,"avatar_url":"https://avatars3.githubusercontent.com/u/351846?v=3","gravatar_id":"","url":"https://api.github.com/users/guard","html_url":"https://github.com/guard","followers_url":"https://api.github.com/users/guard/followers","following_url":"https://api.github.com/users/guard/following{/other_user}","gists_url":"https://api.github.com/users/guard/gists{/gist_id}","starred_url":"https://api.github.com/users/guard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guard/subscriptions","organizations_url":"https://api.github.com/users/guard/orgs","repos_url":"https://api.github.com/users/guard/repos","events_url":"https://api.github.com/users/guard/events{/privacy}","received_events_url":"https://api.github.com/users/guard/received_events","type":"Organization","site_admin":false},"repo":{"id":812610,"name":"guard","full_name":"guard/guard","owner":{"login":"guard","id":351846,"avatar_url":"https://avatars3.githubusercontent.com/u/351846?v=3","gravatar_id":"","url":"https://api.github.com/users/guard","html_url":"https://github.com/guard","followers_url":"https://api.github.com/users/guard/followers","following_url":"https://api.github.com/users/guard/following{/other_user}","gists_url":"https://api.github.com/users/guard/gists{/gist_id}","starred_url":"https://api.github.com/users/guard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guard/subscriptions","organizations_url":"https://api.github.com/users/guard/orgs","repos_url":"https://api.github.com/users/guard/repos","events_url":"https://api.github.com/users/guard/events{/privacy}","received_events_url":"https://api.github.com/users/guard/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/guard/guard","description":"Guard is a command line tool to easily handle events on file system modifications.","fork":false,"url":"https://api.github.com/repos/guard/guard","forks_url":"https://api.github.com/repos/guard/guard/forks","keys_url":"https://api.github.com/repos/guard/guard/keys{/key_id}","collaborators_url":"https://api.github.com/repos/guard/guard/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/guard/guard/teams","hooks_url":"https://api.github.com/repos/guard/guard/hooks","issue_events_url":"https://api.github.com/repos/guard/guard/issues/events{/number}","events_url":"https://api.github.com/repos/guard/guard/events","assignees_url":"https://api.github.com/repos/guard/guard/assignees{/user}","branches_url":"https://api.github.com/repos/guard/guard/branches{/branch}","tags_url":"https://api.github.com/repos/guard/guard/tags","blobs_url":"https://api.github.com/repos/guard/guard/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/guard/guard/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/guard/guard/git/refs{/sha}","trees_url":"https://api.github.com/repos/guard/guard/git/trees{/sha}","statuses_url":"https://api.github.com/repos/guard/guard/statuses/{sha}","languages_url":"https://api.github.com/repos/guard/guard/languages","stargazers_url":"https://api.github.com/repos/guard/guard/stargazers","contributors_url":"https://api.github.com/repos/guard/guard/contributors","subscribers_url":"https://api.github.com/repos/guard/guard/subscribers","subscription_url":"https://api.github.com/repos/guard/guard/subscription","commits_url":"https://api.github.com/repos/guard/guard/commits{/sha}","git_commits_url":"https://api.github.com/repos/guard/guard/git/commits{/sha}","comments_url":"https://api.github.com/repos/guard/guard/comments{/number}","issue_comment_url":"https://api.github.com/repos/guard/guard/issues/comments{/number}","contents_url":"https://api.github.com/repos/guard/guard/contents/{+path}","compare_url":"https://api.github.com/repos/guard/guard/compare/{base}...{head}","merges_url":"https://api.github.com/repos/guard/guard/merges","archive_url":"https://api.github.com/repos/guard/guard/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/guard/guard/downloads","issues_url":"https://api.github.com/repos/guard/guard/issues{/number}","pulls_url":"https://api.github.com/repos/guard/guard/pulls{/number}","milestones_url":"https://api.github.com/repos/guard/guard/milestones{/number}","notifications_url":"https://api.github.com/repos/guard/guard/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/guard/guard/labels{/name}","releases_url":"https://api.github.com/repos/guard/guard/releases{/id}","deployments_url":"https://api.github.com/repos/guard/guard/deployments","created_at":"2010-08-02T16:26:44Z","updated_at":"2017-06-15T17:50:47Z","pushed_at":"2017-06-17T17:28:08Z","git_url":"git://github.com/guard/guard.git","ssh_url":"git@github.com:guard/guard.git","clone_url":"https://github.com/guard/guard.git","svn_url":"https://github.com/guard/guard","homepage":"http://guardgem.org","size":3742,"stargazers_count":5363,"watchers_count":5363,"language":"Ruby","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":462,"mirror_url":null,"open_issues_count":45,"forks":462,"open_issues":45,"watchers":5363,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/guard/guard/pulls/873"},"html":{"href":"https://github.com/guard/guard/pull/873"},"issue":{"href":"https://api.github.com/repos/guard/guard/issues/873"},"comments":{"href":"https://api.github.com/repos/guard/guard/issues/873/comments"},"review_comments":{"href":"https://api.github.com/repos/guard/guard/pulls/873/comments"},"review_comment":{"href":"https://api.github.com/repos/guard/guard/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/guard/guard/pulls/873/commits"},"statuses":{"href":"https://api.github.com/repos/guard/guard/statuses/80c385bf9a2b1d44a96057f62c84dd250411cd22"}}}}
{"actor":{"display_login":"houndci-bot"}}