slack_scratcher 0.1 → 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 56b9028533b252ce83872884a332a85d344f7dc0
4
- data.tar.gz: 670049b263e5c25aa3222311033546af65dfce6b
3
+ metadata.gz: d69bdc6dce5f556068fc0e2920cbc511a0197425
4
+ data.tar.gz: 1bb53fa814baaabff2bc7db34e3a04cb1a7d71a7
5
5
  SHA512:
6
- metadata.gz: a65adf9dc0a91ad769aabfc1b7cf82133c95f19de544f3f368cdf20ab1444c2986e46928e0f1689dc05f8f0651da514c63174a71d1be2b12bff56b904247f408
7
- data.tar.gz: 3ecb3d72f1f036f4c13ae7e706c82c094d75930c2d89d7ee5f8c657e6c0dd9052142df94bb831d021ca8264682825f66a141a981cb4c7982ac89b767eb79b7e4
6
+ metadata.gz: d23b90ecb37f1babfd251c287e3adef18da56ac8a2aa40ddb075de0c48d902a83121bae2fdb90c0b67fee69e77a54624043f208c87c37ca5cdec60e839a0b86c
7
+ data.tar.gz: b5776d10ea833e60f774f3e297cbaffcdd7a72692a490a723705d4fe51347127859390b1f62b804b484d0bb4cbbd58b5a5672049649a28b53cb1e61af7124c98
@@ -5,6 +5,10 @@ require 'faraday'
5
5
 
6
6
  Dotenv.load
7
7
 
8
+ # Importing slack logs from exported fils or API to elasticsearch or
9
+ # other detastores
10
+ #
11
+ # @since 0.0.1
8
12
  module SlackScratcher
9
13
  autoload :Model, 'slack_scratcher/model'
10
14
  autoload :Loader, 'slack_scratcher/loader'
@@ -13,6 +17,8 @@ module SlackScratcher
13
17
  autoload :Error, 'slack_scratcher/error'
14
18
  autoload :Helper, 'slack_scratcher/helper'
15
19
 
20
+ # logger for SlackScratcher Library
21
+ # @return [Logger] Ruby standard logger object
16
22
  def self.logger
17
23
  @logger ||= ::Logger.new(STDOUT)
18
24
  end
@@ -1,6 +1,9 @@
1
1
  module SlackScratcher
2
+ # SlackScratcher Adapter namespace
3
+ # @since 0.0.1
2
4
  module Adapter
3
- autoload :Elasticsearch, 'slack_scratcher/adapter/elasticsearch'
5
+ autoload :Base, 'slack_scratcher/adapter/base'
4
6
  autoload :File, 'slack_scratcher/adapter/file'
7
+ autoload :Elasticsearch, 'slack_scratcher/adapter/elasticsearch'
5
8
  end
6
9
  end
@@ -0,0 +1,27 @@
1
+ module SlackScratcher
2
+ module Adapter
3
+ # Abstract adapter class for storing slack logs
4
+ # @since 0.1
5
+ class Base
6
+ # @ abstract
7
+ def initialize
8
+ fail NotImplementedError
9
+ end
10
+
11
+ # @ abstract
12
+ def send
13
+ fail NotImplementedError
14
+ end
15
+
16
+ # @ abstract
17
+ def timestamp_of_last_channel_log
18
+ fail NotImplementedError
19
+ end
20
+
21
+ # @ abstract
22
+ def ready_index
23
+ fail NotImplementedError
24
+ end
25
+ end
26
+ end
27
+ end
@@ -2,58 +2,113 @@ require 'elasticsearch'
2
2
 
3
3
  module SlackScratcher
4
4
  module Adapter
5
- class Elasticsearch
5
+ # Elasticsearch adapter for storing slack logs.
6
+ #
7
+ # @since 0.0.1
8
+ # @attr_reader [Elasticsearch::Client] client elasticsearch client
9
+ class Elasticsearch < SlackScratcher::Adapter::Base
6
10
  attr_reader :client
7
11
 
12
+ # Initialize SlackScratcher::Adapter::Elasticsearch object.
13
+ #
14
+ # @param [Array] hosts array of Elasticsearch hosts
15
+ # @param [Hash] metadata metadata for storing
16
+ # @option metadata [string] :index index for storing
17
+ # @option metadata [string] :type type for storing
18
+ #
19
+ # @example return Elasticsearch adapter object
20
+ # hosts = ['http://192.168.59.103:9200']
21
+ # metadata = {index: 'slack', type: 'log'}
22
+ # SlackScratcher::Adapter::Elastisearch.new(hosts, metadata)
23
+ #
24
+ # @return [SlackScratcher::Adapter::Elasticsearh]
25
+ # Elasticsearch adapter object
8
26
  def initialize(hosts, metadata)
9
27
  @client = ::Elasticsearch::Client.new hosts: hosts
10
28
  @metadata = metadata
11
29
  end
12
30
 
31
+ # Send data into elastisearch host.
32
+ #
33
+ # @see http://www.rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Actions#bulk-instance_method
34
+ # @param [Array] raw_data slack logs which parsed by loader
35
+ #
36
+ # @example Send log from loader to elastisearch adapter
37
+ # loader.each { |data| adapter.send data }
38
+ #
39
+ # @raise [Elasticsearch::Transport::Transport::Errors::BadRequest]
40
+ # It raise when request is fail
41
+ #
42
+ # @return [Hash] Deserialized Elasticsearch response
43
+ # @return [Boolean] If raw_data is empty, it returns false
13
44
  def send(raw_data)
14
45
  data = format_bulk(raw_data)
15
46
  @client.bulk data unless raw_data.empty?
47
+ false
16
48
  rescue ::Elasticsearch::Transport::Transport::Errors::BadRequest => error
17
49
  puts error
18
50
  end
19
51
 
52
+ # Get last logs' timestamp of specific channel from saved data
53
+ #
54
+ # @param [String] channel_name channel name
55
+ #
56
+ # @example Get saved last log's timestamp of general channel
57
+ # adapter.timestamp_of_last_log 'general' #=> '1426337804.820065'
58
+ #
59
+ # @return [String] Timestamp of last log
60
+ # @return [String] If there isn't saved log, it returns '0'
20
61
  def timestamp_of_last_channel_log(channel_name)
21
62
  request_body = create_body(query_for_last_log(channel_name))
22
63
  log = @client.search request_body
23
64
 
24
- return 0 if log['hits']['total'] == 0
65
+ return '0' if log['hits']['total'] == 0
25
66
  log['hits']['hits'][0]['_source']['ts']
26
67
  end
27
68
 
69
+ # Create index and set mapping for saving slack log data
70
+ #
71
+ # @example Create index and set mapping
72
+ # adapter.ready_index
73
+ #
74
+ # @return [Boolean] If there isn't any problem, it returns true
28
75
  def ready_index
29
76
  unless index?
30
77
  create_index
31
78
  put_mapping
32
79
  end
80
+
81
+ true
33
82
  end
34
83
 
35
84
  private
36
85
 
86
+ # @private
37
87
  def index
38
88
  @metadata[:index]
39
89
  end
40
90
 
91
+ # @private
41
92
  def type
42
93
  @metadata[:type]
43
94
  end
44
95
 
96
+ # @private
45
97
  def index?
46
98
  @client.indices.exists(index: index)
47
99
  end
48
100
 
101
+ # @private
49
102
  def create_index
50
103
  @client.indices.create(index: index)
51
104
  end
52
105
 
106
+ # @private
53
107
  def put_mapping
54
108
  @client.indices.put_mapping create_body(mapping)
55
109
  end
56
110
 
111
+ # @private
57
112
  def mapping
58
113
  {
59
114
  type => {
@@ -72,6 +127,7 @@ module SlackScratcher
72
127
  }
73
128
  end
74
129
 
130
+ # @private
75
131
  def query_for_last_log(channel_name)
76
132
  {
77
133
  size: 1,
@@ -85,6 +141,7 @@ module SlackScratcher
85
141
  }
86
142
  end
87
143
 
144
+ # @private
88
145
  def create_body(body = {})
89
146
  {
90
147
  index: index,
@@ -93,10 +150,12 @@ module SlackScratcher
93
150
  }
94
151
  end
95
152
 
153
+ # @private
96
154
  def format_bulk(data)
97
155
  { body: data.map { |log| format_log(log) } }
98
156
  end
99
157
 
158
+ # @private
100
159
  def format_log(log)
101
160
  { index:
102
161
  {
@@ -1,7 +1,8 @@
1
1
  module SlackScratcher
2
2
  module Adapter
3
- class File
4
-
3
+ # File adapter for storing slack logs.
4
+ # @note Not yet implemented
5
+ class File < SlackScratcher::Adapter::Base
5
6
  end
6
7
  end
7
8
  end
@@ -1,4 +1,6 @@
1
1
  module SlackScratcher
2
+ # SlackScratcher Error namespace
3
+ # @since 0.0.1
2
4
  module Error
3
5
  autoload :UserNotFoundError, 'slack_scratcher/error/user_not_found_error'
4
6
  autoload :SlackApiError, 'slack_scratcher/error/slack_api_error'
@@ -1,5 +1,7 @@
1
1
  module SlackScratcher
2
2
  module Error
3
+ # Error which represent FileNotFound
4
+ # since 0.0.1
3
5
  class FileNotFound < StandardError
4
6
  end
5
7
  end
@@ -1,5 +1,7 @@
1
1
  module SlackScratcher
2
2
  module Error
3
+ # Error which represent SlackApiError
4
+ # since 0.0.1
3
5
  class SlackApiError < StandardError
4
6
  end
5
7
  end
@@ -1,5 +1,7 @@
1
1
  module SlackScratcher
2
2
  module Error
3
+ # Error which represent TokenNotSet
4
+ # since 0.0.1
3
5
  class TokenNotSet < StandardError
4
6
  end
5
7
  end
@@ -1,5 +1,7 @@
1
1
  module SlackScratcher
2
2
  module Error
3
+ # Error which represent UserNotFoundError
4
+ # since 0.0.1
3
5
  class UserNotFoundError < StandardError
4
6
  end
5
7
  end
@@ -1,8 +1,20 @@
1
1
  module SlackScratcher
2
+ # SlackScratcher helper module
3
+ # @since 0.0.1
2
4
  module Helper
5
+ # Index data for searching by specific column
6
+ #
7
+ # @param [Array<Hash>] dataset Dataset
8
+ # @param [String] column column key for indexing
9
+ #
10
+ # @example Index name column
11
+ # data = [{name: 'foo', value: 10}, {name: 'bar', value: 20}]
12
+ # indexed_data = helper.index_data(data, :name)
13
+ # indexed_data['foo'][:value] == 10 #=> true
14
+ #
15
+ # @return [Hash] indexed hash
3
16
  def self.index_data(dataset, column)
4
17
  dataset.map { |data| { data[column] => data } }.inject({}, :merge)
5
18
  end
6
19
  end
7
20
  end
8
-
@@ -1,5 +1,8 @@
1
1
  module SlackScratcher
2
+ # SlackScratcher Loader namespace
3
+ # @since 0.0.1
2
4
  module Loader
5
+ autoload :Base, 'slack_scratcher/loader/base'
3
6
  autoload :File, 'slack_scratcher/loader/file'
4
7
  autoload :Api, 'slack_scratcher/loader/api'
5
8
  end
@@ -2,15 +2,38 @@ require 'slack'
2
2
 
3
3
  module SlackScratcher
4
4
  module Loader
5
- class Api
6
- include Enumerable
7
-
5
+ # Loader class for importing latest slack logs through Slack API
6
+ #
7
+ # @since 0.1
8
+ class Api < SlackScratcher::Loader::Base
9
+ # Duration of waiting between API call
8
10
  WAIT_TIME = 1
9
11
 
12
+ # Initialize SlackScratcher::Loader::Api object.
13
+ #
14
+ # @see https://api.slack.com/web
15
+ #
16
+ # @param [String] token Slack API token. It also can be set by using
17
+ # ENV['SLACK_TOKEN']
18
+ #
19
+ # @example Create File loader obect
20
+ # token = '123456789'
21
+ # SlackScratcher::Loader::Api.new token
22
+ #
23
+ # @return [SlackScratcher::Loader::Api] Api loader object
10
24
  def initialize(token = nil)
11
25
  authenticate_slack(token)
12
26
  end
13
27
 
28
+ # Iterate all log data which is parsed from Slack API.
29
+ #
30
+ # @param [SlackScratcher::Adapter::Base] adapter Datastore adapter
31
+ # for getting when to starting fetch log
32
+ #
33
+ # @example Iterate all logs for priniting contents
34
+ # loader.each { |data| puts data }
35
+ #
36
+ # return [Boolean] If there isn't any ploblem, it returns true
14
37
  def each(adapter)
15
38
  @users || set_users
16
39
 
@@ -24,11 +47,13 @@ module SlackScratcher
24
47
 
25
48
  private
26
49
 
50
+ # @private
27
51
  def set_users
28
52
  @users = users
29
53
  SlackScratcher.logger.info "* Users list refreshed"
30
54
  end
31
55
 
56
+ # @private
32
57
  def check_users(logs)
33
58
  logs
34
59
  .select { |log| log.key? 'user' }
@@ -36,6 +61,7 @@ module SlackScratcher
36
61
  .any? { |user| @users[user].nil? }
37
62
  end
38
63
 
64
+ # @private
39
65
  def parse_log(channel, from)
40
66
  logs = channel_history(channel[:id], from)
41
67
  if check_users(logs)
@@ -44,17 +70,20 @@ module SlackScratcher
44
70
  SlackScratcher::Model::Chats.new(logs, channel, @users).refined_data
45
71
  end
46
72
 
73
+ # @private
47
74
  def authenticate_slack(token)
48
75
  token ||= ENV['SLACK_TOKEN']
49
76
  fail SlackScratcher::Error::TokenNotSet unless token
50
77
  Slack.configure { |config| config.token = token }
51
78
  end
52
79
 
80
+ # @private
53
81
  def channels
54
82
  response = validate_response(Slack.channels_list)
55
83
  index_channels response['channels']
56
84
  end
57
85
 
86
+ # @private
58
87
  def active_channels
59
88
  wait
60
89
 
@@ -62,14 +91,17 @@ module SlackScratcher
62
91
  index_channels filter_active_channels(response['channels'])
63
92
  end
64
93
 
94
+ # @private
65
95
  def filter_active_channels(data)
66
96
  data.select { |channel| channel['is_archived'] == false }
67
97
  end
68
98
 
99
+ # @private
69
100
  def index_channels(data)
70
101
  data.map { |channel| { id: channel['id'], name: channel['name'] } }
71
102
  end
72
103
 
104
+ # @private
73
105
  def users
74
106
  wait
75
107
 
@@ -77,6 +109,7 @@ module SlackScratcher
77
109
  SlackScratcher::Helper.index_data user_list, 'id'
78
110
  end
79
111
 
112
+ # @private
80
113
  def channel_history(channel_id, from, to = Time.now)
81
114
  wait
82
115
 
@@ -90,12 +123,14 @@ module SlackScratcher
90
123
  validate_response Slack.channels_history(attrs), :messages
91
124
  end
92
125
 
126
+ # @private
93
127
  def validate_response(response, key = nil)
94
128
  fail SlackScratcher::Error::ApiError unless response['ok'] == true
95
129
  return response unless key
96
130
  response[key.to_s]
97
131
  end
98
132
 
133
+ # @private
99
134
  def wait
100
135
  sleep WAIT_TIME
101
136
  end
@@ -0,0 +1,19 @@
1
+ module SlackScratcher
2
+ module Loader
3
+ # Abstract loader class for importing slack log data
4
+ # @since 0.1
5
+ class Base
6
+ include Enumerable
7
+
8
+ # @ abstract
9
+ def initialize
10
+ fail NotImplementedError
11
+ end
12
+
13
+ # @ abstract
14
+ def each
15
+ fail NotImplementedError
16
+ end
17
+ end
18
+ end
19
+ end
@@ -2,9 +2,19 @@ require 'oj'
2
2
 
3
3
  module SlackScratcher
4
4
  module Loader
5
- class File
6
- include Enumerable
7
-
5
+ # Loader class for importing slack log data from exported data.
6
+ #
7
+ # @since 0.0.1
8
+ class File < SlackScratcher::Loader::Base
9
+ # Initialize SlackScratcher::Loader::File object.
10
+ #
11
+ # @param [String] target_dir Directory which unarchived log data
12
+ #
13
+ # @example Create File loader obect
14
+ # target_dir = '~/tmp/my_slack-2015-03-16/'
15
+ # SlackScratcher::Loader::File.new target_dir
16
+ #
17
+ # @return [SlackScratcher::Loader::File] File loader object
8
18
  def initialize(target_dir)
9
19
  fail ArgumentError unless ::File.directory?(target_dir)
10
20
 
@@ -13,6 +23,14 @@ module SlackScratcher
13
23
  @channels = channels
14
24
  end
15
25
 
26
+ # Iterate all log data which is parsed from log file in log directory
27
+ #
28
+ # @param [NilClass] _ Not use
29
+ #
30
+ # @example Iterate all logs for priniting contents
31
+ # loader.each { |data| puts data }
32
+ #
33
+ # return [Boolean] If there isn't any ploblem, it returns true
16
34
  def each(_ = nil)
17
35
  files.each do |file|
18
36
  yield parse_log_file(file), file
@@ -23,18 +41,22 @@ module SlackScratcher
23
41
 
24
42
  private
25
43
 
44
+ # @private
26
45
  def get_channel_dir(path)
27
46
  ::File.dirname(path).split('/').last
28
47
  end
29
48
 
49
+ # @private
30
50
  def users
31
51
  load "#{@target}/users.json", 'id'
32
52
  end
33
53
 
54
+ # @private
34
55
  def channels
35
56
  load "#{@target}/channels.json", 'name'
36
57
  end
37
58
 
59
+ # @private
38
60
  def load(target, index_column)
39
61
  fail SlackScratcher::Error::FileNotFound unless ::File.exist? target
40
62
 
@@ -42,27 +64,32 @@ module SlackScratcher
42
64
  SlackScratcher::Helper.index_data channels, index_column
43
65
  end
44
66
 
67
+ # @private
45
68
  def channel_info(log_file)
46
69
  name = get_channel_dir(log_file)
47
70
  { name: name, id: @channels[name]['id'] }
48
71
  end
49
72
 
73
+ # @private
50
74
  def parse_log_file(log_file)
51
75
  channel = channel_info(log_file)
52
76
  logs = Oj.load(::File.read(log_file))
53
77
  SlackScratcher::Model::Chats.new(logs, channel, @users).refined_data
54
78
  end
55
79
 
80
+ # @private
56
81
  def files
57
82
  channel_dirs.inject([]) do |arr, channel|
58
83
  arr + log_files(channel)
59
84
  end
60
85
  end
61
86
 
87
+ # @private
62
88
  def channel_dirs
63
89
  Dir["#{@target}/*/"]
64
90
  end
65
91
 
92
+ # @private
66
93
  def log_files(channel)
67
94
  Dir["#{channel}*.json"]
68
95
  end
@@ -1,4 +1,6 @@
1
1
  module SlackScratcher
2
+ # SlackScratcher model namespace
3
+ # @since 0.0.1
2
4
  module Model
3
5
  autoload :Chats, 'slack_scratcher/model/chats'
4
6
  end
@@ -1,8 +1,26 @@
1
1
  module SlackScratcher
2
2
  module Model
3
+ # Chats model for processing chat data
4
+ #
5
+ # @since 0.0.1
6
+ # @attr_reader [Array] data Original data
7
+ # @attr_reader [Array] refined_data data which is processed
3
8
  class Chats
4
- attr_reader :refined_data, :data
5
-
9
+ attr_reader :data, :refined_data
10
+
11
+ # Initialize SlackScratcher::Model::Chats object. This class is
12
+ # used in Loaders
13
+ #
14
+ # @see SlackScratcher::Loader::File
15
+ # @see SlackScratcher::Loader::Api
16
+ #
17
+ # @param [Array] Data chatting data from loader
18
+ # @param [Hash] channel Hash which have Channel informaiton
19
+ # @option channel [string] :id Channel's unique id
20
+ # @option channel [string] :name Channel's name
21
+ # @param [Hash] users Information of all user
22
+ #
23
+ # @return [SlackScratcher::Model::Chats] Chats model object
6
24
  def initialize(data, channel, users)
7
25
  if !data.is_a?(Array) || !users.is_a?(Hash) || !channel.is_a?(Hash)
8
26
  fail ArgumentError
@@ -17,12 +35,14 @@ module SlackScratcher
17
35
 
18
36
  private
19
37
 
38
+ # @private
20
39
  def refine
21
40
  @data
22
41
  .map { |log| refine_data(log) }
23
42
  .select { |log| !log['uid'].nil? }
24
43
  end
25
44
 
45
+ # @private
26
46
  def refine_data(log)
27
47
  user = find_user(log) unless user
28
48
 
@@ -38,10 +58,12 @@ module SlackScratcher
38
58
  log
39
59
  end
40
60
 
61
+ # @private
41
62
  def create_uid(log)
42
63
  "#{log['datetime']}-#{log['channel_id']}-#{log['username']}"
43
64
  end
44
65
 
66
+ # @private
45
67
  def refine_text(text)
46
68
  text = ":#{text}" if text.is_a?(Symbol)
47
69
 
@@ -50,6 +72,7 @@ module SlackScratcher
50
72
  .gsub(%r{<(http(s)?://.*?)>}) { $1 }
51
73
  end
52
74
 
75
+ # @private
53
76
  def find_user(log)
54
77
  return bot_user(log) if log.key?('username')
55
78
 
@@ -61,12 +84,14 @@ module SlackScratcher
61
84
  unknown_user
62
85
  end
63
86
 
87
+ # @private
64
88
  def undefined_user
65
89
  user = { 'name' => '_unknown_' }
66
90
  user['profile'] = { 'image_32' => '' }
67
91
  user
68
92
  end
69
93
 
94
+ # @private
70
95
  def bot_user(log)
71
96
  user = { 'name' => log['username'] }
72
97
  user['profile'] = { 'image_32' => log['icons']['image_48'] }
@@ -1,26 +1,51 @@
1
1
  module SlackScratcher
2
+ # Slack log router. This import log data from loader, and route them
3
+ # to adapter
4
+ #
5
+ # @since 0.0.1
2
6
  class Router
7
+ # Initalize SlackScratcher::Router object
8
+ #
9
+ # @param [SlackScratcher::Loader::Base] loader
10
+ # @param [SlackScratcher::Adapter::Base] adapter
11
+ #
12
+ # @example Initialize router object
13
+ # SlackScratcher::Router.new(loader, adapter)
14
+ #
15
+ # @return [SlackScratcher::Router] Router object
3
16
  def initialize(loader, adapter)
4
17
  @loader = loader
5
18
  @adapter = adapter
6
19
  end
7
20
 
21
+ # Route logs to adapter
22
+ #
23
+ # @return [Boolean] There isn't any problem, it returns true
8
24
  def route
9
25
  ready
10
26
  _route
27
+ true
11
28
  end
12
29
 
30
+ # Run loop to route logs in real time
31
+ #
32
+ # @return [Boolean] If loop interrupted, it return false
13
33
  def route_loop
14
34
  ready
15
35
  loop { _route }
36
+ rescue Interrupt => error
37
+ SlackScratcher.logger.info error
38
+ false
16
39
  end
17
40
 
18
41
  private
19
42
 
43
+ # @private
20
44
  def ready
21
45
  @adapter.ready_index
22
46
  end
23
47
 
48
+ # @private
24
49
  def _route
25
50
  @loader.each(@adapter) do |data, metadata|
26
51
  if data.empty?
@@ -1,3 +1,4 @@
1
1
  module SlackScratcher
2
- VERSION = '0.1'
2
+ # Current version of SlackScratcher
3
+ VERSION = '0.2'
3
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack_scratcher
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daekwon Kim
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: guard
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +150,20 @@ dependencies:
136
150
  - - ">="
137
151
  - !ruby/object:Gem::Version
138
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: codeclimate-test-reporter
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
139
167
  - !ruby/object:Gem::Dependency
140
168
  name: rubocop
141
169
  requirement: !ruby/object:Gem::Requirement
@@ -151,7 +179,21 @@ dependencies:
151
179
  - !ruby/object:Gem::Version
152
180
  version: '0'
153
181
  - !ruby/object:Gem::Dependency
154
- name: codeclimate-test-reporter
182
+ name: inch
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: yard
155
197
  requirement: !ruby/object:Gem::Requirement
156
198
  requirements:
157
199
  - - ">="
@@ -174,6 +216,7 @@ extra_rdoc_files: []
174
216
  files:
175
217
  - lib/slack_scratcher.rb
176
218
  - lib/slack_scratcher/adapter.rb
219
+ - lib/slack_scratcher/adapter/base.rb
177
220
  - lib/slack_scratcher/adapter/elasticsearch.rb
178
221
  - lib/slack_scratcher/adapter/file.rb
179
222
  - lib/slack_scratcher/error.rb
@@ -184,6 +227,7 @@ files:
184
227
  - lib/slack_scratcher/helper.rb
185
228
  - lib/slack_scratcher/loader.rb
186
229
  - lib/slack_scratcher/loader/api.rb
230
+ - lib/slack_scratcher/loader/base.rb
187
231
  - lib/slack_scratcher/loader/file.rb
188
232
  - lib/slack_scratcher/model.rb
189
233
  - lib/slack_scratcher/model/chats.rb