lobstersbot 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69f8315be206c88998ff12791d13b5fcce6a947b51eed928be0811f14a65700b
4
- data.tar.gz: afae0e599f4a71512dc750baad1a84c7fb9c17807a10a680bdaaf7e86eb3f3f7
3
+ metadata.gz: 68c53d90cc65d235b50060bdf775931f8e72048c7a38e5ea26b1e91431126b6c
4
+ data.tar.gz: 2cdda10f35bf5692f5941926473737e1fccf69db756c32307cbb5ac0b9873253
5
5
  SHA512:
6
- metadata.gz: 70d84d584628b2a6a6d37218a77b0ac95a5a072f17fe5f911a4ac6a485b897d7e14e25600f4ddbd4668a2e7967260ddb389ce6d53a16166ca5d216ca7889aad8
7
- data.tar.gz: 2491273ecb1a31c4950cf6852b45c94ca4cb0b9570242e2502f7b7aac1c2bf546e17cf08a607e8d5f2908d528475c49e7ff3b0d7625cc92ef84fb9705893e4d4
6
+ metadata.gz: ce6a93ce8dae08db804359901291248207428ad74c5c66555cf49f62281427e235cd24431b609265446a75965e35942d07e52af67abcd52ff3c02759a3844016
7
+ data.tar.gz: 500edebf6ce3e758fe2e0a53d1ab501de5319952b8dfa107cbe96b0f19e8c8535ef7f6e5958ec809e5bbe202c0b3cacfbc2cad38f7d3414998ab69a2234d6b67
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: Gem
3
+ on: push
4
+
5
+ jobs:
6
+ rspec:
7
+ name: Rspec
8
+ runs-on: ubuntu-latest
9
+
10
+ steps:
11
+ - name: Checkout code
12
+ uses: actions/checkout@v2
13
+ - name: Setup Ruby
14
+ uses: actions/setup-ruby@v1
15
+ with:
16
+ ruby-version: '2.6'
17
+ - name: Run Suite
18
+ run: |
19
+ gem install bundler
20
+ bundle install --jobs 4 --retry 3
21
+ bundle exec rspec
22
+ rubocop:
23
+ name: Rubocop
24
+ runs-on: ubuntu-latest
25
+
26
+ steps:
27
+ - name: Checkout code
28
+ uses: actions/checkout@v2
29
+ - name: Setup Ruby
30
+ uses: actions/setup-ruby@v1
31
+ with:
32
+ ruby-version: '2.6'
33
+ - name: Run Rubocop
34
+ run: |
35
+ gem install bundler
36
+ bundle install --jobs 4 --retry 3
37
+ bundle exec rubocop
@@ -0,0 +1,253 @@
1
+ # Please do not 'fix' style issues without a compelling, metrics-driven
2
+ # argument that a style change will materially improve cod equality.
3
+ # https://github.com/lobsters/lobsters/pull/460
4
+
5
+ # Project setup:
6
+ require:
7
+ - rubocop-rspec
8
+ AllCops:
9
+ Include:
10
+ - '**/*.rb'
11
+ - '**/Rakefile'
12
+ - '**/config.ru'
13
+ - '**/*.rake'
14
+ Exclude:
15
+ - Gemfile
16
+ - 'bin/**/*'
17
+ - 'db/**/*'
18
+ - 'vendor/**/*'
19
+
20
+ # Cop configuration:
21
+
22
+ # Bundler
23
+
24
+ # Gemspec
25
+
26
+ # Layout
27
+ Layout/AccessModifierIndentation:
28
+ EnforcedStyle: outdent
29
+ Layout/ArrayAlignment:
30
+ Enabled: false
31
+ Layout/CaseIndentation:
32
+ EnforcedStyle: end
33
+ Layout/ElseAlignment:
34
+ Enabled: false
35
+ Layout/EmptyLineAfterGuardClause:
36
+ Enabled: false
37
+ Layout/EmptyLinesAroundExceptionHandlingKeywords:
38
+ Enabled: false
39
+ Layout/EndAlignment:
40
+ EnforcedStyleAlignWith: variable
41
+ Layout/FirstHashElementIndentation:
42
+ EnforcedStyle: consistent
43
+ Layout/HashAlignment:
44
+ Enabled: false
45
+ Layout/LineLength:
46
+ Max: 100
47
+ Layout/MultilineMethodCallBraceLayout:
48
+ Enabled: false
49
+ Layout/MultilineMethodCallIndentation:
50
+ Enabled: false
51
+ Layout/SpaceAroundOperators:
52
+ Enabled: false
53
+ Layout/SpaceInsideBlockBraces:
54
+ EnforcedStyle: space
55
+ SpaceBeforeBlockParameters: false
56
+ Layout/SpaceInsideRangeLiteral:
57
+ Enabled: false
58
+
59
+ # Lint
60
+ Lint/SuppressedException:
61
+ Enabled: false
62
+ Lint/RaiseException:
63
+ Enabled: true
64
+ Lint/StructNewOverride:
65
+ Enabled: true
66
+
67
+ # Metrics
68
+ Metrics/AbcSize:
69
+ Enabled: false
70
+ Metrics/BlockLength:
71
+ Enabled: false
72
+ Metrics/BlockNesting:
73
+ Enabled: false
74
+ Metrics/ClassLength:
75
+ Enabled: false
76
+ Metrics/CyclomaticComplexity:
77
+ Enabled: false
78
+ Metrics/MethodLength:
79
+ Enabled: false
80
+ Metrics/ModuleLength:
81
+ Enabled: false
82
+ Metrics/ParameterLists:
83
+ Enabled: false
84
+ Metrics/PerceivedComplexity:
85
+ Enabled: false
86
+
87
+ # Naming
88
+ Naming/AccessorMethodName:
89
+ Enabled: false
90
+ Naming/MemoizedInstanceVariableName:
91
+ Enabled: false
92
+ Naming/PredicateName:
93
+ Enabled: false
94
+ # disabled until class vaiables in extras become constants
95
+ Naming/MethodParameterName:
96
+ Enabled: false
97
+ Naming/VariableName:
98
+ Enabled: false
99
+
100
+ # Performance
101
+
102
+ # RSpec
103
+ RSpec/ExampleLength:
104
+ Enabled: false
105
+ RSpec/MultipleExpectations:
106
+ Enabled: false
107
+ RSpec/DescribedClass:
108
+ Enabled: false
109
+ RSpec/MessageSpies:
110
+ Enabled: false
111
+ RSpec/VerifiedDoubles:
112
+ Enabled: false
113
+ RSpec/NotToNot:
114
+ Enabled: false
115
+ RSpec/ContextWording:
116
+ Enabled: false
117
+ RSpec/ExpectChange:
118
+ Enabled: false
119
+ RSpec/HookArgument:
120
+ Enabled: false
121
+ RSpec/ExampleWording:
122
+ Enabled: false
123
+ RSpec/NamedSubject:
124
+ Enabled: false
125
+ RSpec/NestedGroups:
126
+ Enabled: false
127
+ RSpec/AnyInstance:
128
+ Enabled: false
129
+ RSpec/UnspecifiedException:
130
+ Enabled: false
131
+ RSpec/InstanceVariable:
132
+ Enabled: false
133
+ RSpec/BeforeAfterAll:
134
+ Enabled: false
135
+ RSpec/DescribeClass:
136
+ Enabled: false
137
+ Capybara/FeatureMethods:
138
+ Enabled: false
139
+
140
+ # Security
141
+
142
+ # Style
143
+ Style/AndOr:
144
+ EnforcedStyle: conditionals
145
+ Style/BlockDelimiters:
146
+ Enabled: false
147
+ Style/BlockComments:
148
+ Enabled: false
149
+ Style/CommentedKeyword:
150
+ Enabled: false
151
+ Style/ClassVars:
152
+ Enabled: false
153
+ Style/ConditionalAssignment:
154
+ Enabled: false
155
+ # It would be nice to have this on, but I'm not up for writing 66 of these in
156
+ # the process of addressing the initial 4,489 cop warnings.
157
+ Style/Documentation:
158
+ Enabled: false
159
+ Exclude: [db/migrate/**/*, spec/**/*, test/**/*]
160
+ Style/DoubleNegation:
161
+ Enabled: false
162
+ Style/EachWithObject:
163
+ Enabled: false
164
+ Style/ExpandPathArguments:
165
+ Enabled: false
166
+ Style/FormatString:
167
+ Enabled: false
168
+ Style/FormatStringToken:
169
+ Enabled: false
170
+ Style/FrozenStringLiteralComment:
171
+ EnforcedStyle: never
172
+ Style/GuardClause:
173
+ Enabled: false
174
+ Style/HashEachMethods:
175
+ Enabled: true
176
+ Style/HashSyntax:
177
+ EnforcedStyle: no_mixed_keys
178
+ Style/HashTransformKeys:
179
+ Enabled: true
180
+ Style/HashTransformValues:
181
+ Enabled: true
182
+ Style/IfInsideElse:
183
+ Enabled: false
184
+ Style/IfUnlessModifier:
185
+ Enabled: false
186
+ Style/InverseMethods:
187
+ Enabled: false
188
+ Style/Lambda:
189
+ Enabled: false
190
+ Style/LineEndConcatenation:
191
+ Enabled: false
192
+ Style/MethodDefParentheses:
193
+ Enabled: false
194
+ Style/MultilineBlockChain:
195
+ Enabled: false
196
+ Style/MultilineTernaryOperator:
197
+ Enabled: false
198
+ Style/NegatedIf:
199
+ EnforcedStyle: postfix
200
+ Style/NegatedWhile:
201
+ Enabled: false
202
+ Style/Next:
203
+ Enabled: false
204
+ Style/NonNilCheck:
205
+ Enabled: false
206
+ Style/NumericPredicate:
207
+ Enabled: false
208
+ Style/ParallelAssignment:
209
+ Enabled: false
210
+ Style/PercentLiteralDelimiters:
211
+ Enabled: false
212
+ Style/PerlBackrefs:
213
+ Enabled: false
214
+ Style/RaiseArgs:
215
+ EnforcedStyle: compact
216
+ Style/RedundantBegin:
217
+ Enabled: false
218
+ Style/RedundantParentheses:
219
+ Enabled: false
220
+ Style/RedundantReturn:
221
+ Enabled: false
222
+ Style/RedundantSelf:
223
+ Enabled: false
224
+ Style/RescueModifier:
225
+ Enabled: false
226
+ Style/RescueStandardError:
227
+ EnforcedStyle: implicit
228
+ Style/RegexpLiteral:
229
+ AllowInnerSlashes: true
230
+ Style/SafeNavigation:
231
+ Enabled: false
232
+ Style/SignalException:
233
+ Enabled: false
234
+ Style/StringLiterals:
235
+ Enabled: false
236
+ Style/SymbolArray:
237
+ EnforcedStyle: brackets
238
+ Style/TrailingCommaInArguments:
239
+ Enabled: false
240
+ Style/TrailingCommaInArrayLiteral:
241
+ EnforcedStyleForMultiline: consistent_comma
242
+ Style/TrailingCommaInHashLiteral:
243
+ EnforcedStyleForMultiline: consistent_comma
244
+ Style/WhileUntilDo:
245
+ Enabled: false
246
+ Style/WhileUntilModifier:
247
+ Enabled: false
248
+ Style/WordArray:
249
+ Enabled: false
250
+ Style/YodaCondition:
251
+ Enabled: false
252
+ Style/ZeroLengthPredicate:
253
+ Enabled: false
@@ -1,12 +1,14 @@
1
- #!/usr/local/bin/ruby -w
1
+ #!/usr/bin/env -S ruby -w
2
2
 
3
3
  require 'lobstersbot'
4
4
 
5
5
  class Bot < Summer::Connection
6
+ include Lobstersbot::SummerPatches
6
7
  include Lobstersbot::PluggableConnection
7
-
8
+
8
9
  include Lobstersbot::Tell
9
10
  include Lobstersbot::Rss
11
+ include Lobstersbot::Salute
10
12
  end
11
13
 
12
14
  Bot.new("irc.freenode.net")
@@ -7,10 +7,12 @@ require 'timers'
7
7
 
8
8
  require 'lobstersbot/version'
9
9
  require 'lobstersbot/rss_reader'
10
+ require 'lobstersbot/summer_patches'
10
11
  require 'lobstersbot/pluggable_connection'
11
12
 
12
13
  require 'lobstersbot/plugins/tell'
13
14
  require 'lobstersbot/plugins/rss'
15
+ require 'lobstersbot/plugins/salute'
14
16
 
15
17
  module Lobstersbot
16
18
  class Error < StandardError; end
@@ -1,45 +1,73 @@
1
1
  module Lobstersbot
2
2
  module PluggableConnection
3
- def config_dir(file)
4
- File.join(ARGV[0], file)
3
+ @@triggers = [
4
+ # The default command handler.
5
+ [
6
+ 0,
7
+ /\A\.(?<command>[a-z]+)\s(?<message>.+)\z/i,
8
+ lambda do |bot, channel, nick, match|
9
+ bot.evaluate(:"on_#{match[:command]}", channel, nick, match[:message])
10
+ end,
11
+ ],
12
+ ]
13
+
14
+ def self.triggers
15
+ @@triggers
5
16
  end
6
-
7
- def load_config
8
- @config = HashWithIndifferentAccess.new(YAML.load_file(config_dir('lobstersbot.yml')))
17
+
18
+ def self.included(mod)
19
+ mod.extend(ClassMethods)
9
20
  end
10
-
21
+
22
+ module ClassMethods
23
+ def add_trigger(priority, regex, handler)
24
+ PluggableConnection.triggers << [priority, regex, handler]
25
+ end
26
+ end
27
+
28
+ def respond(channel, nick, msg)
29
+ privmsg("#{nick}: #{msg}", channel)
30
+ end
31
+
11
32
  def did_start_up
12
33
  pp ARGV
13
34
  @timers = Timers::Group.new
14
35
  @memory = PStore.new(config_dir('memory.pstore'), true)
15
-
36
+
37
+ # Sort the triggers by priority.
38
+ @@triggers.sort! {|a, b| b[0] <=> a[0] }
39
+
16
40
  @timers.every(60) { evaluate(:frequently) }
17
41
  Thread.new { loop { @timers.wait } }
18
42
  end
19
-
43
+
20
44
  def channel_message(sender, channel, message)
21
- request = message.match(/\A\.(?<command>[a-z]+)\s(?<message>.+)\z/i)
22
- return unless request
23
- response_proc = ->(msg) { privmsg("#{sender[:nick]}: #{msg}", channel) }
24
-
25
- evaluate(:"on_#{request[:command]}", sender[:nick], request[:message], response_proc)
45
+ match = nil
46
+
47
+ _, _, handler = @@triggers.find do |trigger|
48
+ match = message.match(trigger[1])
49
+ !match.nil?
50
+ end
51
+ return unless match
52
+
53
+ handler.call(self, channel, sender[:nick], match)
26
54
  end
27
-
55
+
28
56
  def join_event(sender, channel)
29
57
  response_proc = ->(msg) { privmsg("#{sender[:nick]}: #{msg}", channel) }
30
58
  evaluate(:seen, sender[:nick], response_proc)
31
59
  end
32
-
60
+
33
61
  def evaluate(group, *args)
34
- matching = public_methods.select { |m| m.to_s.start_with?(group.to_s) }
35
-
62
+ matching = public_methods.select {|m| m.to_s.start_with?(group.to_s) }
63
+
36
64
  matching.each do |match|
37
65
  slice_name = match.to_s.sub("#{group}_", '').to_sym
38
66
  @memory.transaction do
39
- slice = @memory[slice_name] ||= Hash.new
67
+ slice = @memory[slice_name] ||= {}
40
68
  method(match).call(slice, *args)
41
69
  end
42
70
  end
43
71
  end
44
72
  end
45
- end
73
+ end
@@ -1,13 +1,13 @@
1
1
  module Lobstersbot
2
2
  module Rss
3
3
  def frequently_post_stories(
4
- memory,
4
+ memory,
5
5
  reader = RssReader.new('https://lobste.rs/newest.rss')
6
6
  )
7
7
  reader.call(memory[:last_run]).each do |story|
8
- @config[:channels].each { |c| privmsg(story, c) }
8
+ @config[:channels].each {|c| privmsg(story, c) }
9
9
  end
10
10
  memory[:last_run] = Time.now.to_i
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -0,0 +1,18 @@
1
+ module Lobstersbot
2
+ module Salute
3
+ @@claws = ['(V)', '(\\/)', '(\\_/)', 'V', 'v', '(v)']
4
+ @@faces = ['_!_!_', '.v.', '_00_']
5
+
6
+ def salute_user(channel)
7
+ claws = @@claws.sample 2
8
+ face = @@faces.sample
9
+ lobster = claws[0] + face + claws[1]
10
+ privmsg(lobster, channel)
11
+ end
12
+
13
+ def self.included(mod)
14
+ handler = ->(bot, channel, _nick, _match) { bot.salute_user channel }
15
+ mod.add_trigger(100, /\AV.v.V\z/i, handler)
16
+ end
17
+ end
18
+ end
@@ -1,19 +1,19 @@
1
1
  module Lobstersbot
2
2
  module Tell
3
- def on_tell(memory, nick, message, response)
3
+ def on_tell(memory, channel, nick, message)
4
4
  parsed = message.match(/(?<target>[^\s]+)\s(?<message>.+)/)
5
5
  return unless parsed
6
-
6
+
7
7
  target = parsed[:target]
8
- memory[target] ||= Array.new
8
+ memory[target] ||= []
9
9
  memory[target] << "#{nick}: #{parsed[:message]}"
10
-
11
- response.call("I'll pass that along when #{target} is around.")
10
+
11
+ respond(channel, nick, "I'll pass that along when #{target} is around.")
12
12
  end
13
-
13
+
14
14
  def seen_tell(memory, nick, response)
15
15
  return unless memory[nick].is_a? Array
16
- memory[nick].each { |msg| response.call(msg) }
16
+ memory[nick].each {|msg| response.call(msg) }
17
17
  end
18
18
  end
19
- end
19
+ end
@@ -3,31 +3,31 @@ require 'rss'
3
3
 
4
4
  module Lobstersbot
5
5
  class RssReader
6
- FORMAT = '%s %s (%s) - %s'
7
- USERNAME_REGXP = /\((?<username>.+)\)/i
8
-
6
+ FORMAT = '%s %s (%s) - %s'.freeze
7
+ USERNAME_REGXP = /\((?<username>.+)\)/i # rubocop:disable Style/MutableConstant
8
+
9
9
  def initialize(endpoint, open_proc = URI.method(:open))
10
10
  @endpoint = endpoint
11
11
  @open = open_proc
12
12
  end
13
-
13
+
14
14
  def call(not_before)
15
15
  feed = @open.call(@endpoint)
16
16
  rss = RSS::Parser.parse(feed)
17
-
17
+
18
18
  rss.items.map do |item|
19
19
  item.pubDate.to_i > not_before ? format_item(item) : nil
20
20
  end.compact
21
21
  end
22
-
23
- private
24
-
22
+
23
+ private
24
+
25
25
  def format_item(item)
26
26
  id = item.guid.content
27
- categories = item.categories.map(&:content).map { |n| "[%s]" % n}
27
+ categories = item.categories.map(&:content).map {|n| "[%s]" % n }
28
28
  username = item.author.match(USERNAME_REGXP)[:username]
29
-
29
+
30
30
  FORMAT % [item.title, categories.join(' '), username, id]
31
31
  end
32
32
  end
33
- end
33
+ end
@@ -0,0 +1,27 @@
1
+ module Lobstersbot
2
+ module SummerPatches
3
+ def config_dir(file)
4
+ File.join(ARGV[0], file)
5
+ end
6
+
7
+ def load_config
8
+ @config = HashWithIndifferentAccess.new(YAML.load_file(config_dir('lobstersbot.yml')))
9
+ end
10
+
11
+ def connect!
12
+ @connection = TCPSocket.open(server, port)
13
+
14
+ if config[:use_ssl]
15
+ cert_file = File.read(config_dir('client.pem'))
16
+ context = OpenSSL::SSL::SSLContext.new
17
+ context.key = OpenSSL::PKey.read(cert_file)
18
+ context.crt = OpenSSL::X509::Certificate.new(cert_file)
19
+
20
+ @connection = OpenSSL::SSL::SSLSocket.new(@connection, context).connect
21
+ end
22
+
23
+ response("USER #{config[:nick]} #{config[:nick]} #{config[:nick]} #{config[:nick]}")
24
+ response("NICK #{config[:nick]}")
25
+ end
26
+ end
27
+ end
@@ -1,3 +1,3 @@
1
1
  module Lobstersbot
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -27,6 +27,9 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency "rake", "~> 10.0"
28
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
29
 
30
+ spec.add_development_dependency "rubocop", "~> 1.8"
31
+ spec.add_development_dependency "rubocop-rspec", "~> 2.1.0"
32
+
30
33
  spec.add_runtime_dependency 'summer', '~> 1.0'
31
34
  spec.add_runtime_dependency 'timers', '~> 4.1'
32
35
  spec.add_runtime_dependency 'rss', '~> 0.2.9'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lobstersbot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hunter Madison
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-17 00:00:00.000000000 Z
11
+ date: 2021-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.1.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.1.0
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: summer
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -102,8 +130,10 @@ executables:
102
130
  extensions: []
103
131
  extra_rdoc_files: []
104
132
  files:
133
+ - ".github/workflows/gem.yml"
105
134
  - ".gitignore"
106
135
  - ".rspec"
136
+ - ".rubocop.yml"
107
137
  - ".travis.yml"
108
138
  - Gemfile
109
139
  - LICENSE.txt
@@ -115,8 +145,10 @@ files:
115
145
  - lib/lobstersbot.rb
116
146
  - lib/lobstersbot/pluggable_connection.rb
117
147
  - lib/lobstersbot/plugins/rss.rb
148
+ - lib/lobstersbot/plugins/salute.rb
118
149
  - lib/lobstersbot/plugins/tell.rb
119
150
  - lib/lobstersbot/rss_reader.rb
151
+ - lib/lobstersbot/summer_patches.rb
120
152
  - lib/lobstersbot/version.rb
121
153
  - lobstersbot.gemspec
122
154
  homepage: https://github.com/lobsters/lobstersbot