senrigan 0.1.0

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.
@@ -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: []