senrigan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3dd57d4a1bb78a31824d5b4fbc24623ec1a54f106b520b00c5aad01fa6f3e60d
4
+ data.tar.gz: 61e15d7158f255b72ba1fd0dad5cf8a1a4e86f1b57727a8e4a493a685c90a483
5
+ SHA512:
6
+ metadata.gz: 187e341609c16b8e4930ff8118e4eace9cebbf58ba7760620a104e69e5ddc3806cbee26aaeb096df155995584e0f255477d6c95c4f051ef30c745289b83b0955
7
+ data.tar.gz: 4f296c1bbf8835aa1ff81b2e2fa8a0dd4cd85c0160110e640cfe42e882a4ae046c15bd66e961b1727423bcc5e5ef45dc981905f4ef73af803b683052e0c597a6
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
@@ -0,0 +1,83 @@
1
+ AllCops:
2
+ Exclude:
3
+ - tmp/**/*
4
+ - vendor/**/*
5
+ TargetRubyVersion: 2.5
6
+ DisplayCopNames: true
7
+
8
+ # use japanese :)
9
+ Style/AsciiComments:
10
+ Enabled: false
11
+
12
+ # use method chain ( avoid use `end.compact` )
13
+ #
14
+ # hoge.map { |item|
15
+ # item.piyo
16
+ # }.compact
17
+ Style/BlockDelimiters:
18
+ Enabled: false
19
+
20
+ # no document
21
+ Style/Documentation:
22
+ Enabled: false
23
+
24
+ # use `!!hoge`
25
+ Style/DoubleNegation:
26
+ Enabled: false
27
+
28
+ # empty case is useful
29
+ #
30
+ # case
31
+ # when user.admin?
32
+ # ...
33
+ # when user.active?
34
+ # ...
35
+ # else
36
+ # ...
37
+ # end
38
+ Style/EmptyCaseCondition:
39
+ Enabled: false
40
+
41
+ # my preference :)
42
+ Style/EmptyMethod:
43
+ EnforcedStyle: expanded
44
+
45
+ # use `-> {}` syntax
46
+ Style/Lambda:
47
+ Enabled: false
48
+
49
+ # see Style/BlockDelimiters
50
+ Style/MultilineBlockChain:
51
+ Enabled: false
52
+
53
+ # I feel `.zero?` difficult to understand...
54
+ Style/NumericPredicate:
55
+ Enabled: false
56
+
57
+ # %w[a b c] or %i[a b c] ?
58
+ Style/SymbolArray:
59
+ Enabled: false
60
+
61
+ # incompatible DSL
62
+ Layout/EmptyLinesAroundArguments:
63
+ Enabled: false
64
+
65
+ # incompatible DSL
66
+ Metrics/BlockLength:
67
+ Enabled: false
68
+
69
+ # incompatible DSL
70
+ Metrics/ClassLength:
71
+ Enabled: false
72
+
73
+ # my preference :)
74
+ Metrics/LineLength:
75
+ Max: 120
76
+
77
+ # my preference :(
78
+ Metrics/MethodLength:
79
+ Max: 25
80
+
81
+ # :(
82
+ Metrics/AbcSize:
83
+ Max: 30
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in senrigan.gemspec
8
+ gemspec
@@ -0,0 +1,77 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ senrigan (0.1.0)
5
+ colorize
6
+ faye-websocket
7
+ gemoji
8
+ slack-ruby-client
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (5.2.1.1)
14
+ concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ i18n (>= 0.7, < 2)
16
+ minitest (~> 5.1)
17
+ tzinfo (~> 1.1)
18
+ ast (2.4.0)
19
+ colorize (0.8.1)
20
+ concurrent-ruby (1.1.3)
21
+ eventmachine (1.2.7)
22
+ faraday (0.15.4)
23
+ multipart-post (>= 1.2, < 3)
24
+ faraday_middleware (0.12.2)
25
+ faraday (>= 0.7.4, < 1.0)
26
+ faye-websocket (0.10.7)
27
+ eventmachine (>= 0.12.0)
28
+ websocket-driver (>= 0.5.1)
29
+ gemoji (3.0.0)
30
+ gli (2.18.0)
31
+ hashie (3.6.0)
32
+ i18n (1.1.1)
33
+ concurrent-ruby (~> 1.0)
34
+ jaro_winkler (1.5.1)
35
+ minitest (5.11.3)
36
+ multipart-post (2.0.0)
37
+ parallel (1.12.1)
38
+ parser (2.5.3.0)
39
+ ast (~> 2.4.0)
40
+ powerpack (0.1.2)
41
+ rainbow (3.0.0)
42
+ rake (10.5.0)
43
+ rubocop (0.60.0)
44
+ jaro_winkler (~> 1.5.1)
45
+ parallel (~> 1.10)
46
+ parser (>= 2.5, != 2.5.1.1)
47
+ powerpack (~> 0.1)
48
+ rainbow (>= 2.2.2, < 4.0)
49
+ ruby-progressbar (~> 1.7)
50
+ unicode-display_width (~> 1.4.0)
51
+ ruby-progressbar (1.10.0)
52
+ slack-ruby-client (0.13.1)
53
+ activesupport
54
+ faraday (>= 0.9)
55
+ faraday_middleware
56
+ gli
57
+ hashie
58
+ websocket-driver
59
+ thread_safe (0.3.6)
60
+ tzinfo (1.2.5)
61
+ thread_safe (~> 0.1)
62
+ unicode-display_width (1.4.0)
63
+ websocket-driver (0.7.0)
64
+ websocket-extensions (>= 0.1.0)
65
+ websocket-extensions (0.1.3)
66
+
67
+ PLATFORMS
68
+ ruby
69
+
70
+ DEPENDENCIES
71
+ bundler (~> 1.16)
72
+ rake (~> 10.0)
73
+ rubocop
74
+ senrigan!
75
+
76
+ BUNDLED WITH
77
+ 1.16.2
@@ -0,0 +1,24 @@
1
+ # Senrigan
2
+
3
+ > Senrigan is terminal viewer of slack
4
+
5
+ ## Usage
6
+
7
+ ### install
8
+
9
+ ```bash
10
+ $ gem install senrigan
11
+ ```
12
+
13
+ ### how to run
14
+
15
+ You need legacy tokens (https://api.slack.com/custom-integrations/legacy-tokens)
16
+
17
+ ```bash
18
+ $ SLACK_TOKEN='xxxxxxx' senrigan
19
+ ```
20
+
21
+ ## Supported event
22
+
23
+ - message
24
+ - message changed
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ task default: :spec
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'senrigan'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/senrigan'
5
+
6
+ Senrigan::CLI.new(ARGV).run!
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'senrigan/version'
4
+ require 'senrigan/entities/base'
5
+ require 'senrigan/entities/attachment'
6
+ require 'senrigan/entities/channel'
7
+ require 'senrigan/entities/message'
8
+ require 'senrigan/entities/message_change_event'
9
+ require 'senrigan/entities/user'
10
+ require 'senrigan/adapter'
11
+ require 'senrigan/formatter'
12
+ require 'senrigan/cli'
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+ require 'cgi'
5
+ require 'gemoji'
6
+ require 'slack-ruby-client'
7
+
8
+ module Senrigan
9
+ class Adapter
10
+ def initialize(options = {})
11
+ @options = options
12
+ setup_slack
13
+ @client = ::Slack::Web::Client.new
14
+ @handlers = []
15
+ @message_list = []
16
+ end
17
+
18
+ def on(&block)
19
+ @handlers.push(block)
20
+ end
21
+
22
+ def connect!
23
+ loop do
24
+ regenerate_cache
25
+ @rtm = nil
26
+ begin
27
+ @rtm = ::Slack::RealTime::Client.new
28
+ @rtm.on(:message, &method(:on_message))
29
+ @rtm.on(:close, &method(:on_close))
30
+ @rtm.start!
31
+ rescue StandardError => e
32
+ STDOUT.puts e.inspect if ENV['DEBUG'].to_i != 0
33
+ end
34
+ sleep 5
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def setup_slack
41
+ ::Slack.configure do |config|
42
+ config.token = access_token
43
+ end
44
+ end
45
+
46
+ def access_token
47
+ return ENV['SLACK_TOKEN'] if ENV['SLACK_TOKEN']
48
+
49
+ raise 'please set `ENV["SLACK_TOKEN"]` !'
50
+ end
51
+
52
+ def regenerate_cache
53
+ @channel_caches = (
54
+ @client.channels_list['channels'] +
55
+ @client.groups_list['groups']
56
+ ).map { |c| [c['id'], c] }.to_h
57
+ @user_caches = @client.users_list['members'].map { |u| [u['id'], u] }.to_h
58
+ end
59
+
60
+ def fetch_user(user_id)
61
+ @user_caches[user_id] ||= begin
62
+ resp = @client.users_info(
63
+ user: user_id
64
+ )
65
+ resp['channel'] || OpenStruct.new
66
+ end
67
+ end
68
+
69
+ def fetch_channel(channel_id)
70
+ @channel_caches[channel_id] ||= begin
71
+ data =
72
+ case channel_id.first
73
+ when 'C'
74
+ resp = @client.channels_info(
75
+ channel: channel_id
76
+ )
77
+ resp['channel']
78
+ when 'G'
79
+ resp = @client.groups_info(
80
+ channel: channel_id
81
+ )
82
+ resp['group']
83
+ else
84
+ OpenStruct.new(name: channel_id, is_private: true)
85
+ end
86
+ data || OpenStruct.new(name: channel_id, is_private: false)
87
+ end
88
+ end
89
+
90
+ def on_message(msg)
91
+ entity =
92
+ case
93
+ when msg.subtype == 'message_changed'
94
+ create_message_change_event_entity(msg)
95
+ when msg.subtype.nil?, msg.subtype == 'bot_message'
96
+ create_message_entity(msg)
97
+ end
98
+ return unless entity
99
+
100
+ @message_list.push(entity)
101
+
102
+ @handlers.each do |handler|
103
+ handler.call(entity)
104
+ end
105
+ end
106
+
107
+ def create_message_entity(msg)
108
+ Entities::Message.new(
109
+ ts: msg.ts,
110
+ channel: pick_channel_from_message(msg),
111
+ user: pick_user_from_message(msg),
112
+ content: format_text(msg.text),
113
+ attachments: create_attachment_entities(msg.attachments),
114
+ parent: msg.thread_ts ? @message_list.find { |m| m.ts == msg.thread_ts } : nil
115
+ )
116
+ end
117
+
118
+ def create_message_change_event_entity(msg)
119
+ channel = pick_channel_from_message(msg)
120
+ user = pick_user_from_message(msg)
121
+ parent = msg.message.thread_ts ? @message_list.find { |m| m.ts == msg.message.thread_ts } : nil
122
+ Entities::MessageChangeEvent.new(
123
+ ts: msg.ts,
124
+ edited_message: Entities::Message.new(
125
+ ts: msg.message.ts,
126
+ channel: channel,
127
+ user: user,
128
+ content: format_text(msg.message.text),
129
+ attachments: create_attachment_entities(msg.message.attachments),
130
+ parent: parent
131
+ ),
132
+ previous_message: Entities::Message.new(
133
+ ts: msg.previous_message.ts,
134
+ channel: channel,
135
+ user: user,
136
+ content: format_text(msg.previous_message.text),
137
+ attachments: create_attachment_entities(msg.previous_message.attachments),
138
+ parent: parent
139
+ )
140
+ )
141
+ end
142
+
143
+ def create_attachment_entities(attachments)
144
+ return [] unless attachments
145
+
146
+ attachments.map do |attachment|
147
+ Entities::Attachment.new(
148
+ title: format_text(attachment.title),
149
+ text: format_text(attachment.text),
150
+ title_link: attachment.title_link
151
+ )
152
+ end
153
+ end
154
+
155
+ def pick_channel_from_message(msg)
156
+ case
157
+ when msg.channel
158
+ channel = fetch_channel(msg.channel)
159
+ Entities::Channel.new(
160
+ name: channel&.name || msg.channel,
161
+ is_private: channel ? (channel.is_private || channel.is_group || channel.is_mpim) : false
162
+ )
163
+ end
164
+ end
165
+
166
+ def pick_user_from_message(msg)
167
+ case
168
+ when msg.username
169
+ Entities::User.new(
170
+ name: msg.username,
171
+ is_bot: true
172
+ )
173
+ when msg.user, msg.message&.user
174
+ user = fetch_user(msg.user || msg.message.user)
175
+ name = [user&.profile&.display_name, user&.name, msg.user].find { |n| !n.nil? && !n.empty? }
176
+ Entities::User.new(
177
+ name: name.to_s,
178
+ is_bot: user&.is_bot
179
+ )
180
+ else
181
+ Entities::User.new(name: '', is_bot: true)
182
+ end
183
+ end
184
+
185
+ def format_text(src_text)
186
+ text = src_text.to_s.dup
187
+ text.gsub!(/\\b/, '')
188
+ text.gsub!(/\<\@(U[^>\|]+)\>/) do
189
+ "@#{fetch_user(Regexp.last_match(1)).name}"
190
+ end
191
+ text.gsub!(/\<\@(U[^\|]+)\|([^>]+)\>/) do
192
+ "@#{fetch_user(Regexp.last_match(1)).name}"
193
+ end
194
+ text.gsub!(/\<\#(C[^>\|]+)\>/) do
195
+ "##{fetch_channel(Regexp.last_match(1)).name}"
196
+ end
197
+ text.gsub!(/\<\#(C[^\|]+)\|([^>]+)\>/) do
198
+ "##{fetch_channel(Regexp.last_match(1)).name}"
199
+ end
200
+ text.gsub!(/<[^\|>]+\|([^>]+)>/, '\1')
201
+ text.gsub!(/<|>/, '')
202
+ text.gsub!(/:([^\:]+):/) do
203
+ emoji = Emoji.find_by_alias(Regexp.last_match(1))
204
+ emoji ? "#{emoji.raw} " : ":#{Regexp.last_match(1)}:"
205
+ end
206
+ text.gsub!(/\!(here|channel|group)/, '@\1')
207
+ CGI.unescapeHTML(text)
208
+ end
209
+
210
+ def on_close(message)
211
+ puts message.inspect
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senrigan
4
+ class CLI
5
+ def initialize(argv)
6
+ @argv = argv.clone
7
+ end
8
+
9
+ def run!
10
+ clear_terminal
11
+ show_header
12
+ formatter = Senrigan::Formatter.new
13
+ adapter = Senrigan::Adapter.new
14
+ adapter.on do |entity|
15
+ formatter.format_print(entity)
16
+ end
17
+ adapter.connect!
18
+ rescue Interrupt
19
+ exit 0
20
+ end
21
+
22
+ private
23
+
24
+ def clear_terminal
25
+ print "\e[H\e[2J"
26
+ end
27
+
28
+ def show_header
29
+ STDOUT.puts "[Senrigan v.#{Senrigan::VERSION}]"
30
+ STDOUT.puts
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senrigan
4
+ module Entities
5
+ class Attachment < Base
6
+ attr_accessor :title, :text, :title_link
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senrigan
4
+ module Entities
5
+ class Base
6
+ def initialize(attributes = {})
7
+ attributes.each do |k, v|
8
+ public_send("#{k}=", v)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senrigan
4
+ module Entities
5
+ class Channel < Base
6
+ attr_accessor :name, :is_private
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senrigan
4
+ module Entities
5
+ class Message < Base
6
+ attr_accessor :ts, :channel, :user, :content, :parent
7
+ attr_writer :attachments
8
+
9
+ def attachments
10
+ @attachments ||= []
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senrigan
4
+ module Entities
5
+ class MessageChangeEvent < Base
6
+ attr_accessor :ts, :edited_message, :previous_message
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senrigan
4
+ module Entities
5
+ class User < Base
6
+ attr_accessor :name, :is_bot
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'colorize'
4
+
5
+ module Senrigan
6
+ class Formatter
7
+ def initialize
8
+ end
9
+
10
+ def format(entity)
11
+ case entity
12
+ when Entities::Message
13
+ format_message(entity)
14
+ when Entities::MessageChangeEvent
15
+ format_message_change_event(entity)
16
+ else
17
+ entity.inspect
18
+ end
19
+ end
20
+
21
+ def format_print(entity)
22
+ str = format(entity)
23
+ STDOUT.puts str unless str.empty?
24
+ end
25
+
26
+ def format_message(entity)
27
+ lines = []
28
+ lines.push format_header(entity)
29
+ lines.push entity.content unless entity.content.empty?
30
+ entity.attachments.each do |attachment|
31
+ lines.push format_attachment(attachment)
32
+ end
33
+ lines.push format_parent(entity.parent) if entity.parent
34
+ lines.join("\n")
35
+ end
36
+
37
+ def format_message_change_event(entity)
38
+ if entity.edited_message.content == entity.previous_message.content &&
39
+ !entity.edited_message.attachments.empty? && entity.previous_message.attachments.empty?
40
+ entity.edited_message.attachments.map { |a| format_attachment(a) }.join("\n")
41
+ else
42
+ format_message(entity.edited_message)
43
+ end
44
+ end
45
+
46
+ def format_header(entity)
47
+ [
48
+ "@#{entity.user.name}#{entity.user.is_bot ? ' [App]' : ''}".to_s.colorize(:light_blue),
49
+ 'in',
50
+ "#{entity.channel.is_private ? '🔒 ' : '#'}#{entity.channel.name}".colorize(:light_green),
51
+ Time.at(entity.ts.to_i).strftime('%H:%M').colorize(:light_black)
52
+ ].join(' ')
53
+ end
54
+
55
+ def format_parent(entity)
56
+ lines = []
57
+ lines.push [
58
+ '>',
59
+ "@#{entity.user.name}#{entity.user.is_bot ? ' [App]' : ''}".to_s,
60
+ Time.at(entity.ts.to_i).strftime('%H:%M')
61
+ ].join(' ').colorize(:light_black)
62
+ lines.push "> #{entity.content.split(/\r?\n/).join("\n> ")}".colorize(:light_black)
63
+ lines.join("\n")
64
+ end
65
+
66
+ def format_attachment(attachment)
67
+ lines = []
68
+ lines.push attachment.title.to_s.colorize(:green) unless attachment.title.to_s.empty?
69
+ lines.push attachment.text.to_s.colorize(:green) unless attachment.text.to_s.empty?
70
+ lines.push attachment.title_link.to_s.colorize(:green) unless attachment.title_link.to_s.empty?
71
+ lines.join("\n")
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senrigan
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'senrigan/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'senrigan'
9
+ spec.version = Senrigan::VERSION
10
+ spec.authors = ['ru_shalm']
11
+ spec.email = ['ru_shalm@hazimu.com']
12
+ spec.summary = 'Slack timeline viewer'
13
+ spec.homepage = 'https://github.com/rutan/senrigan'
14
+
15
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
16
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ end
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'colorize'
23
+ spec.add_dependency 'faye-websocket'
24
+ spec.add_dependency 'gemoji'
25
+ spec.add_dependency 'slack-ruby-client'
26
+ spec.add_development_dependency 'bundler', '~> 1.16'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rubocop'
29
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: senrigan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ru_shalm
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-12-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faye-websocket
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: gemoji
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: slack-ruby-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.16'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.16'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description:
112
+ email:
113
+ - ru_shalm@hazimu.com
114
+ executables:
115
+ - senrigan
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - ".rubocop.yml"
121
+ - Gemfile
122
+ - Gemfile.lock
123
+ - README.md
124
+ - Rakefile
125
+ - bin/console
126
+ - bin/setup
127
+ - exe/senrigan
128
+ - lib/senrigan.rb
129
+ - lib/senrigan/adapter.rb
130
+ - lib/senrigan/cli.rb
131
+ - lib/senrigan/entities/attachment.rb
132
+ - lib/senrigan/entities/base.rb
133
+ - lib/senrigan/entities/channel.rb
134
+ - lib/senrigan/entities/message.rb
135
+ - lib/senrigan/entities/message_change_event.rb
136
+ - lib/senrigan/entities/user.rb
137
+ - lib/senrigan/formatter.rb
138
+ - lib/senrigan/version.rb
139
+ - senrigan.gemspec
140
+ homepage: https://github.com/rutan/senrigan
141
+ licenses: []
142
+ metadata: {}
143
+ post_install_message:
144
+ rdoc_options: []
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ requirements: []
158
+ rubyforge_project:
159
+ rubygems_version: 2.7.6
160
+ signing_key:
161
+ specification_version: 4
162
+ summary: Slack timeline viewer
163
+ test_files: []