iirc 0.2.8 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d1d6ae434bb4e2301cffa91ad030d6a1a154ad0d9fc402fea6baad7ee3840011
4
- data.tar.gz: 1bb87fe5fa933ed85884c677617646daab7a98fdd691392d87e738132b4ea5eb
3
+ metadata.gz: 89d3e4727f759400cf52bf6a8cb23b365d62259ef32fd977c6fcaab0d542fa53
4
+ data.tar.gz: fc476e509a2ca6e620d6b93bbde705113136926e574860b05bc5508c332f8e51
5
5
  SHA512:
6
- metadata.gz: '090d2add141ab9a775e22d216d5b7baeef87a5f19026ede39d0717954a9c1df3cc5c63df68b169f4925654bea04c25f50aaf5a503471be153b9f86c3dbfbab59'
7
- data.tar.gz: 9770fb0e1eb3a491e9978f95331468349a5554f1b621c7bad1487b14d6251df2ebd5b0fd0b940afbd91412442a9dec22de5b27ca34c84d4927cd3f572bf0acfb
6
+ metadata.gz: c9cbf42882b4aeb2ae080266750d540d5f834a6c55be22d8b75541c7ca4b521492eacae055c21a3bdb716ca691e3db8a685c79d918c353df324ed8f42b9f168d
7
+ data.tar.gz: 98d82cf28be02e06e32dd8c6978eb0470ca486c6b9f898fb0642e244e2edbaa99f2c0df9aa9fc4491610968d72736cfae05aba8dfddd1fe04fcdf72681389503
data/CHANGELOG.md CHANGED
@@ -1,3 +1,37 @@
1
+ ## [0.4.0] - 2022-03-27
2
+
3
+ - [Numerics] Add module with constants imported from ircdocs.horse
4
+ - Run `rake numerics` to re-import.
5
+
6
+ - [IIRC.run,IIRC.dial] Support passing a symbol as ssl_context
7
+ - e.g. ssl_context: :no_verify instead of ssl_context: IIRC::SSL.no_verify
8
+
9
+ - The AmbientEvents modules have been reorganised
10
+ - AmbientVerbs is now Ambient::Verbs
11
+ - AmbientEvents => Ambient::Events
12
+ - AmbientEvents::{LabeledRequests,ReplyTarget} => Ambient::{LabeledRequests,ReplyTarget}
13
+
14
+ - #ambient_reply_target() has been replaced with #reply_target(evt=ambient_event)
15
+
16
+ - [Bot.run] Set nick to class name if no param is given
17
+ - `MyBot.run('irc.libera.chat')` is enough to connect to Libera as 'MyBot'
18
+
19
+ ## [0.3.0] - 2022-03-26
20
+
21
+ - [Bot] Include ReplyTarget
22
+ - [Hooks] Refactor
23
+ - Add AcceptInvites module
24
+ - Improve Greeter example
25
+ - [IIRC.run,IIRC.dial] now accept local_host, local_port keyword arguments
26
+
27
+ ## [0.2.9] - 2022-03-24
28
+
29
+ - Add reply target concept (Bot::ReplyTarget)
30
+ - The reply target of an event is the sender's nick when we are its target,
31
+ and equal to the regular target otherwise.
32
+ - The ambient verb methods now target the reply target of the ambient event by default.
33
+ - Should make writing actions more convenient.
34
+
1
35
  ## [0.2.8] - 2022-03-22
2
36
 
3
37
  - Add MIT license
data/Rakefile CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "bundler/gem_tasks"
4
4
  require "rake/testtask"
5
+ require "rdoc/task"
5
6
 
6
7
  Rake::TestTask.new(:test) do |t|
7
8
  t.libs << "test"
@@ -9,4 +10,68 @@ Rake::TestTask.new(:test) do |t|
9
10
  t.test_files = FileList["test/**/*_test.rb"]
10
11
  end
11
12
 
13
+ RDoc::Task.new do |rd|
14
+ rd.rdoc_files.include("lib/**/*.rb")
15
+ rd.options = ["--all"]
16
+ end
17
+
18
+ task :numerics do
19
+ require 'yaml'
20
+ require 'open-uri'
21
+
22
+ data = YAML.load URI.open('https://raw.githubusercontent.com/ircdocs/irc-defs/gh-pages/_data/numerics.yaml')
23
+ revision = data['file']['revision']
24
+
25
+ puts "Loaded numerics.yaml revision #{revision}"
26
+
27
+ open(File.join(__dir__, 'lib/iirc/numerics.rb'), 'w+') do |out|
28
+ out << <<~HEADER
29
+ module IIRC
30
+ # Definitions imported from ircdocs.horse
31
+ # @version #{revision}
32
+ # @see https://raw.githubusercontent.com/ircdocs/irc-defs/gh-pages/_data/numerics.yaml
33
+ # @see https://defs.ircdocs.horse/defs/numerics.html
34
+ module Numerics
35
+ HEADER
36
+
37
+ values = data['values'].reject { |v| v['obsolete'] }
38
+ counts = values.map { |v| v['name'] }.tally
39
+
40
+ constants = {}
41
+
42
+ for row in values
43
+ out << " # #{row['comment'].squeeze(' ').tr("\r", '').gsub("\n", ' ').strip}\n" if row['comment']
44
+ out << " # @format #{row['numeric']} #{row['format'].strip}\n" if row['format']
45
+
46
+ name = row['name']
47
+ if counts[name] > 1 and row['origin']
48
+ name += '_' + row['origin'].gsub(/[^[:alnum:]]/, '_').gsub(/_{2,}/, '_').sub(/_$/, '').upcase
49
+ end
50
+ if constants[name]
51
+ name += '_ALT'
52
+ if constants[name]
53
+ fail <<~MSG
54
+ Couldn't derive a unique name for #{name}.
55
+ Previous source: #{constants[name].inspect}
56
+ MSG
57
+ end
58
+ end
59
+
60
+ constants[name] = row
61
+
62
+ out << " #{name} = #{row['numeric'].to_sym.inspect}"
63
+ out << "\n"
64
+ end
65
+
66
+ out << <<~FOOTER
67
+ end
68
+ end
69
+ FOOTER
70
+ end
71
+
72
+ puts "%d numerics." % data['values'].count
73
+ system('wc', File.join(__dir__, 'lib/iirc/numerics.rb'))
74
+ end
75
+
12
76
  task default: :test
77
+
data/examples/greeter.rb CHANGED
@@ -3,9 +3,10 @@ require "iirc"
3
3
  class Greeter < IIRC::Bot
4
4
  include AutoJoin
5
5
  include Verbs
6
+ include PrintIO
6
7
 
7
8
  def on_join(evt)
8
- say evt.target, "Hello #{evt.sender.nick}!"
9
+ say evt.target, "Hello #{evt.sender.nick}!" unless me === evt.sender
9
10
  end
10
11
 
11
12
  def autojoin_channels
@@ -0,0 +1,22 @@
1
+ module IIRC
2
+ module Bot::AcceptInvites
3
+ # Override this to decide whether we should accept a given invite.
4
+ # By default, all invites are accepted.
5
+ # @param [Event]
6
+ # @return [true] if we should join the channel
7
+ def accept_invite?(evt)
8
+ true
9
+ end
10
+
11
+ private
12
+ def configure_accept_invites
13
+ on :invite, :accept_invites
14
+ end
15
+
16
+ def accept_invites(evt)
17
+ if me === evt.target and accept_invite?(evt)
18
+ join evt.args[1]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,50 +1,61 @@
1
+ require_relative "reply_target"
2
+
1
3
  module IIRC
2
- module Bot::AmbientEvents
3
- private
4
- def configure_ambient_events
5
- hook :set_ambient_event
6
- end
4
+ module Bot::Ambient
5
+ module Events
6
+ private
7
+ def configure_ambient_events
8
+ hook :set_ambient_event
9
+ end
7
10
 
8
- def ambient_event
9
- Thread.current[:ambient_event]
10
- end
11
+ def ambient_event
12
+ Thread.current[:ambient_event]
13
+ end
11
14
 
12
- def ambient_target; ambient_event&.target; end
13
- def ambient_sender; ambient_event&.sender; end
15
+ def ambient_target; ambient_event&.target; end
16
+ def ambient_sender; ambient_event&.sender; end
14
17
 
15
- def set_ambient_event(evt)
16
- Thread.current[:ambient_event] = evt
17
- end
18
+ def set_ambient_event(evt)
19
+ Thread.current[:ambient_event] = evt
20
+ end
21
+
22
+ def with_ambient_event(evt)
23
+ initial_event = ambient_event
24
+ set_ambient_event(evt)
25
+ begin
26
+ yield evt
27
+ ensure
28
+ set_ambient_event(initial_event)
29
+ end
30
+ end
31
+ end
18
32
 
19
- def with_ambient_event(evt)
20
- initial_event = ambient_event
21
- set_ambient_event(evt)
22
- begin
23
- yield evt
24
- ensure
25
- set_ambient_event(initial_event)
33
+ module LabeledRequests
34
+ def labeled_request(*)
35
+ initial_evt = ambient_event
36
+ super do |reply|
37
+ with_ambient_event(initial_evt) { yield reply }
26
38
  end
27
39
  end
28
- end
40
+ end
29
41
 
30
- module Bot::AmbientVerbs
31
- include Bot::AmbientEvents
42
+ module ReplyTarget
43
+ def reply_target(evt=ambient_event) super end
44
+ end
32
45
 
33
- def join(channel=ambient_target) super end
34
- def part(channel=ambient_target, reason='') super end
35
- def msg(channel=ambient_target, msg) super end
36
- def act(channel=ambient_target, msg) super end
37
- def cycle(channel=ambient_target, reason='') super end
38
- def mode(channel=ambient_target, mode) super end
39
- alias :say :msg
40
- end
46
+ module Verbs
47
+ include Events
48
+ include ReplyTarget
41
49
 
42
- module Bot::AmbientEvents::LabeledRequests
43
- def labeled_request(*)
44
- initial_evt = ambient_event
45
- super do |reply|
46
- with_ambient_event(initial_evt) { yield reply }
47
- end
50
+ def join(channel=reply_target) super end
51
+ def part(channel=reply_target, reason='') super end
52
+ def msg(target=reply_target, msg) super end
53
+ def act(target=reply_target, msg) super end
54
+ def cycle(channel=reply_target, reason='') super end
55
+ def mode(target=reply_target, mode) super end
56
+ alias :say :msg
48
57
  end
58
+
59
+ include Verbs
49
60
  end
50
- end
61
+ end
@@ -4,6 +4,18 @@ module IIRC
4
4
  @hooks ||= Hash.new { |h,v| h[v] = Set.new }
5
5
  end
6
6
 
7
+ def run
8
+ lines { |line|
9
+ begin
10
+ evt = parse(line)
11
+ fire! evt.verb, evt
12
+ rescue Exception => ex
13
+ puts ex.message
14
+ puts ex.backtrace
15
+ end
16
+ }
17
+ end
18
+
7
19
  def on verb=nil, action=nil, &blk
8
20
  if action and blk
9
21
  define_singleton_method(action, blk)
@@ -17,10 +29,6 @@ module IIRC
17
29
  end
18
30
  end
19
31
 
20
- def hook action=nil, &blk
21
- on nil, action, &blk
22
- end
23
-
24
32
  def off verb, action=nil, &blk
25
33
  action ||= blk
26
34
  if action
@@ -30,14 +38,12 @@ module IIRC
30
38
  end
31
39
  end
32
40
 
41
+ def hook action=nil, &blk
42
+ on nil, action, &blk
43
+ end
44
+
33
45
  def fire! verb, *args, **kwargs
34
- for action in hooks[nil]
35
- call action, *args, **kwargs
36
- end
37
- if respond_to? :"on_#{verb}"
38
- send(:"on_#{verb}", *args, **kwargs)
39
- end
40
- for action in hooks[verb]
46
+ for action in hook_seq(verb)
41
47
  call action, *args, **kwargs
42
48
  end
43
49
  rescue StopIteration
@@ -54,16 +60,9 @@ module IIRC
54
60
  end
55
61
  end
56
62
 
57
- def run
58
- lines { |line|
59
- begin
60
- evt = parse(line)
61
- fire! evt.verb, evt
62
- rescue Exception => ex
63
- puts ex.message
64
- puts ex.backtrace
65
- end
66
- }
67
- end
63
+ protected
64
+ def hook_seq(verb)
65
+ [*hooks[nil], (:"on_#{verb}" if respond_to?(:"on_#{verb}")), *hooks[verb]].compact
66
+ end
68
67
  end
69
- end
68
+ end
@@ -4,7 +4,7 @@ module IIRC
4
4
  autoload :IRCParser, 'ircparser'
5
5
 
6
6
  def parse(line)
7
- msg = IRCParser::Message.parse(line.chomp)
7
+ msg = IRCParser::Message.parse(line.tr("\r", '').chomp)
8
8
 
9
9
  Event.new.tap { |evt|
10
10
  evt.sender = IRCParser::RFCWireFormat.__stringify_prefix(msg.prefix) if msg.prefix
@@ -0,0 +1,14 @@
1
+ module IIRC
2
+ module Bot::ReplyTarget
3
+ # The +reply_target+ of an event is the sender's nickname when _we_ are the
4
+ # +target+. Otherwise, it returns the regular +target+.
5
+ #
6
+ # It lets us reply to events without having to repeat the `(me ===
7
+ # target) ? sender.nick : target` logic used to make sure we don't message
8
+ # ourselves when we receive a direct PRIVMSG, NOTICE, etc.
9
+
10
+ def reply_target(evt)
11
+ (me === evt.target) ? evt.sender.nick : evt.target
12
+ end
13
+ end
14
+ end
data/lib/iirc/bot.rb CHANGED
@@ -30,7 +30,7 @@ module IIRC
30
30
  end
31
31
 
32
32
  private def ensure_registration_info!
33
- me.username ||= me.nick.downcase
33
+ me.username ||= me.nick&.downcase
34
34
  me.realname ||= me.nick
35
35
  raise ArgumentError.new('no nick given') unless me.nick && !me.nick.empty?
36
36
  end
data/lib/iirc/event.rb CHANGED
@@ -10,8 +10,7 @@ module IIRC
10
10
  end
11
11
 
12
12
  def sender=(v)
13
- v.extend Sender if v
14
- @sender = v
13
+ @sender = IIRC::Sender(v)
15
14
  end
16
15
 
17
16
  def args=(v)