blur 1.8.6 → 2.1.6

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.
@@ -1,140 +1,156 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Blur
4
- # The +Script+ class is used for encapsulating dynamically loaded ruby scripts.
5
- #
6
- # The {Script#Script} method is then used to shape the DSL-language to make
7
- # writing Blur scripts a breeze.
8
- #
9
- # @todo add examples in the documentation
10
- # @see Script#Script
11
- class Script
12
- include Logging
13
- include Evaluable
14
- include DSL
15
-
16
- ExtensionNotFoundError = Class.new StandardError
17
- Emissions = [:connection_ready, :topic_change, :user_rename, :message,
18
- :private_message, :user_entered, :user_left, :user_quit,
19
- :user_kicked, :topic, :user_mode, :channel_mode,
20
- :channel_created, :channel_who_reply]
21
-
22
- # @return the path in which the script remains.
23
- attr_accessor :__path
24
- # Can be used inside the script to act with the client itself.
25
- # @return [Network::Client] the client delegate.
26
- attr_accessor :__client
27
- # @return [Array] a list of handled emissions.
28
- attr_accessor :__emissions
29
-
30
- # A list of extensions.
31
- @@__extensions = []
32
-
33
- # Find and evaluate script extensions.
34
- def self.load_extensions!
35
- root_path = File.dirname $0
36
-
37
- Dir.glob("#{root_path}/extensions/*.rb").each do |path|
38
- extension = Extension.new path
39
- extension.__client = self
40
- extension.extension_loaded if extension.respond_to? :extension_loaded
41
-
42
- @@__extensions << extension
4
+ module Commands
5
+ # This is a command look-up-table with an autoincrementing index.
6
+ class CommandLUT
7
+ attr_accessor :commands
8
+
9
+ def initialize
10
+ @index = -1
11
+ @commands = {}
12
+ end
13
+
14
+ # Inserts the command to the LUT.
15
+ #
16
+ # @returns the index.
17
+ def << command
18
+ @commands[command] = @index += 1
19
+ @index
43
20
  end
44
21
  end
45
22
 
46
- # "Unload" all script extensions.
47
- def self.unload_extensions!
48
- @@__extensions.clear
23
+ module ClassMethods
24
+ # Creates a new command.
25
+ #
26
+ # @example
27
+ # command! '!ping' do |user, channel, args|
28
+ # channel.say "#{user}: pong"
29
+ # end
30
+ def command! command, *_args, &block
31
+ id = (command_lut << command)
32
+ define_method :"_command_#{id}", &block
33
+ end
49
34
  end
50
-
51
- # Check to see if the script has been evaluated.
52
- def evaluated?; @__evaluated end
53
-
54
- # Instantiates a script and evaluates the contents which remain in +path+.
55
- def initialize path
56
- @__path = path
57
- @__evaluated = false
58
- @__emissions = []
59
-
60
- if evaluate_source_file path
61
- cache.load if Cache.exists? @__name
62
-
63
- Emissions.each do |emission|
64
- @__emissions.push emission if respond_to? emission
65
- end
66
-
67
- __send__ :loaded if respond_to? :loaded
68
- __send__ :module_init if respond_to? :module_init
35
+
36
+ def self.included klass
37
+ class << klass
38
+ attr_accessor :command_lut
69
39
  end
40
+
41
+ klass.extend ClassMethods
42
+ klass.command_lut = CommandLUT.new
43
+ klass.register! message: lambda { |script, user, channel, line|
44
+ command, args = line.split ' ', 2
45
+ return unless command
46
+
47
+ if (id = klass.command_lut.commands[command.downcase])
48
+ script.__send__ :"_command_#{id}", user, channel, args
49
+ end
50
+ }
70
51
  end
71
-
72
- # Make it a DSL-way of writing a script.
73
- #
74
- # @example
75
- # Script :example do
76
- # def connection_ready network
77
- # #
78
- # end
79
- # end
80
- def Script name, options = {}, &block
81
- @__name = name
82
-
83
- extensions = options[:using] || options[:uses]
84
-
85
- # Automatically used extensions.
86
- if extensions
87
- extensions.each {|extension_name| using extension_name }
52
+ end
53
+
54
+ class SuperScript
55
+ class << self
56
+ attr_accessor :name, :authors, :version, :description, :events
57
+
58
+ # Sets the author.
59
+ #
60
+ # @example
61
+ # Author 'John Doe <john.doe@example.com>'
62
+ def Author *authors
63
+ @authors = authors
88
64
  end
89
65
 
90
- # Automatically included modules.
91
- if options[:includes]
92
- options[:includes].each{|module_name| self.extend module_name }
66
+ # Sets the description.
67
+ #
68
+ # @example
69
+ # Description 'This is an example script.'
70
+ def Description description
71
+ @description = description
72
+ end
73
+
74
+ # Sets the version.
75
+ #
76
+ # @example
77
+ # Version '1.0.0'
78
+ def Version version
79
+ @version = version
93
80
  end
94
-
95
- instance_eval &block
96
-
97
- true
98
- end
99
81
 
100
- # Add script extension and define a method with the same name as
101
- # the extension.
102
- def using *extension_names
103
- extension_names.each do |extension_name|
104
- if extension = @@__extensions.find{|ext| ext.__name.to_s == extension_name.to_s }
105
- extension.extension_used self if extension.respond_to? :extension_used
106
- self.metaclass.send :define_method, :"#{extension_name}" do
107
- return extension
82
+ # Registers events to certain functions.
83
+ #
84
+ # @example
85
+ # register! message: :on_message, connection_ready: :connected
86
+ def register! *args
87
+ args.each do |events|
88
+ case events
89
+ when Hash
90
+ events.each do |event, method_name|
91
+ register_event! event, method_name
92
+ end
93
+ when Array
94
+ register! *events
95
+ when Symbol
96
+ register_event! events
108
97
  end
109
- else
110
- raise ExtensionNotFoundError, "Extension not found: #{extension_name}"
111
98
  end
112
99
  end
113
- end
114
-
115
- # Unload the script and save the cache, if present.
116
- def unload!
117
- cache.save if @__cache
118
- __send__ :unloaded if respond_to? :unloaded
119
100
 
120
- @__cache = nil
101
+ # Adds the given event +name+ and the name of the method to call once the
102
+ # event is emitted.
103
+ def register_event! name, method_name = name
104
+ (@events[name] ||= []) << method_name
105
+ end
106
+
107
+ def to_s
108
+ inspect
109
+ end
110
+
111
+ def inspect
112
+ %(#<SuperScript:0x#{object_id.to_s 16}>)
113
+ end
114
+
115
+ alias author authors
116
+ alias Authors Author
121
117
  end
122
118
 
123
- # Access another script with name +name+.
124
- #
125
- # @return [Script] the script with the name +name+, or nil.
119
+ # Called when when the superscript has been loaded and added to the list of
120
+ # superscripts.
121
+ def self.init; end
122
+
123
+ # Called right before the script is being removed from the list of
124
+ # superscripts.
125
+ def self.deinit; end
126
+
127
+ # Reference to the main client that holds the script.
128
+ attr_accessor :_client_ref
129
+
130
+ # Script-specific configuration that is read from the main configuration
131
+ # file.
132
+ attr_accessor :config
133
+
134
+ attr_accessor :cache
135
+
136
+ # Called right before the instance of the script is being removed.
137
+ def unloaded; end
138
+
139
+ # Gets the instantiated script with +name+.
126
140
  def script name
127
- @__client.scripts.find { |script| script.__name == name }
141
+ _client_ref.scripts[name]
128
142
  end
129
-
130
- # Get the cache, if none, instantiate a new cache.
131
- def cache
132
- @__cache ||= Cache.new self
133
- end
134
-
135
- # Convert it to a debug-friendly format.
143
+
144
+ # Gets a human-readable representation of the script.
136
145
  def inspect
137
- File.basename @__path
146
+ "#<Script(#{self.class.name.inspect}) " \
147
+ "@author=#{self.class.author.inspect} " \
148
+ "@version=#{self.class.version.inspect} " \
149
+ "@description=#{self.class.description.inspect}>"
150
+ end
151
+
152
+ def to_s
153
+ inspect
138
154
  end
139
155
  end
140
156
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blur
4
+ class ScriptCache
5
+ def initialize script_name, path, hash
6
+ @script_name = script_name
7
+ @path = path
8
+ @hash = hash
9
+ end
10
+
11
+ # Gets a cache +value+ by its +key+.
12
+ def [] key
13
+ @hash[key]
14
+ end
15
+
16
+ # Sets the cache +key+ to the provided +value+.
17
+ def []= key, value
18
+ @hash[key] = value
19
+ end
20
+
21
+ # Saves the cache as a YAML file.
22
+ def save
23
+ directory = File.dirname @path
24
+
25
+ Dir.mkdir directory unless File.directory? directory
26
+
27
+ File.open @path, 'w' do |file|
28
+ YAML.dump @hash, file
29
+ end
30
+ end
31
+
32
+ # Loads the cache file for +script_name+ in +cache_dir+ if it exists.
33
+ def self.load script_name, cache_dir
34
+ cache_path = File.join cache_dir, "#{script_name}.yml"
35
+
36
+ if File.exist? cache_path
37
+ object = YAML.load_file cache_path
38
+
39
+ ScriptCache.new script_name, cache_path, object
40
+ else
41
+ ScriptCache.new script_name, cache_path, {}
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blur
4
+ # The +User+ class is used for encapsulating a user and its properties.
5
+ #
6
+ # The user owns a reference to its parent channel.
7
+ #
8
+ # Modes can be set for a user, but Blur is not
9
+ # {http://www.irc.org/tech_docs/005.html ISupport}-compliant yet.
10
+ #
11
+ # @todo make so that channels *and* users belongs to the network, and not
12
+ # like now where the user belongs to the channel, resulting in multiple
13
+ # user instances.
14
+ class User
15
+ # @return [String] the users nickname.
16
+ attr_accessor :nick
17
+ # @return [String] the users username.
18
+ attr_accessor :name
19
+ # @return [String] the users hostname.
20
+ attr_accessor :host
21
+ # @return [String] all the modes set on the user.
22
+ attr_accessor :modes
23
+ # @return [Network] a reference to the network.
24
+ attr_accessor :network
25
+ attr_accessor :channels
26
+
27
+ # @return [Hash<String, String>] a map of symbols to channel user modes.
28
+ COMMON_SYMBOL_MODES = {
29
+ '@' => 'o',
30
+ '+' => 'v',
31
+ '%' => 'h',
32
+ '&' => 'a',
33
+ '~' => 'q'
34
+ }.freeze
35
+
36
+ # Check to see if the user is an admin (+a)
37
+ def admin?
38
+ @modes.include? 'a'
39
+ end
40
+
41
+ # Check to see if the user has voice (+v)
42
+ def voice?
43
+ @modes.include? 'v'
44
+ end
45
+
46
+ # Check to see if the user is the owner (+q)
47
+ def owner?
48
+ @modes.include? 'q'
49
+ end
50
+
51
+ # Check to see if the user is an operator (+o)
52
+ def operator?
53
+ @modes.include? 'o'
54
+ end
55
+
56
+ # Check to see if the user is an half-operator (+h)
57
+ def half_operator?
58
+ @modes.include? 'h'
59
+ end
60
+
61
+ # Instantiate a user with a nickname.
62
+ def initialize nick, network = nil
63
+ @nick = nick
64
+ @modes = String.new
65
+ @channels = []
66
+ @network = network
67
+
68
+ return unless (modes = prefix_to_mode(nick[0]))
69
+
70
+ @nick = nick[1..]
71
+ @modes = modes
72
+ end
73
+
74
+ # Merge the users mode corresponding to the leading character (+ or -).
75
+ #
76
+ # @param [String] modes the modes to merge with.
77
+ def merge_modes modes
78
+ addition = true
79
+
80
+ modes.each_char do |char|
81
+ case char
82
+ when '+'
83
+ addition = true
84
+ when '-'
85
+ addition = false
86
+ else
87
+ addition ? @modes.concat(char) : @modes.delete!(char)
88
+ end
89
+ end
90
+ end
91
+
92
+ # Send a private message to the user.
93
+ #
94
+ # @param [String] message the message to send.
95
+ def say message
96
+ @network.say self, message
97
+ end
98
+
99
+ # Convert it to a debug-friendly format.
100
+ def inspect
101
+ %(#<#{self.class.name}:0x#{object_id.to_s 16} @nick=#{@nick.inspect}>)
102
+ end
103
+
104
+ # Called when YAML attempts to save the object, which happens when a
105
+ # scripts cache contains this user and the script is unloaded.
106
+ def to_yaml options = {}
107
+ @nick.to_yaml options
108
+ end
109
+
110
+ # Get the users nickname.
111
+ def to_s
112
+ @nick
113
+ end
114
+
115
+ private
116
+
117
+ # Translate a nickname-prefix to a mode character.
118
+ def prefix_to_mode prefix
119
+ COMMON_SYMBOL_MODES[prefix]
120
+ end
121
+ end
122
+ end
@@ -1,13 +1,13 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Blur
4
4
  # The current version of Blur.
5
- Version = "1.8.6"
5
+ VERSION = '2.1.6'
6
6
 
7
7
  # Get the current version.
8
8
  #
9
9
  # @return [String] The current version of Blur.
10
10
  def self.version
11
- Version
11
+ VERSION
12
12
  end
13
13
  end
data/library/blur.rb CHANGED
@@ -1,36 +1,63 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'pp'
4
3
  require 'yaml'
5
- require 'majic'
6
4
  require 'socket'
5
+ require 'base64'
7
6
  require 'ostruct'
8
7
  require 'openssl'
8
+
9
+ require 'deep_merge/rails_compat'
9
10
  require 'eventmachine'
11
+ require 'ircparser'
10
12
 
11
13
  # Require all library files.
12
- require 'blur/version'
13
- require 'blur/client'
14
- require 'blur/evaluable'
15
- require 'blur/script/dsl'
16
- require 'blur/extension'
17
- require 'blur/script'
18
- require 'blur/network'
19
- require 'blur/encryption'
20
- require 'blur/enhancements'
21
- require 'blur/script/cache'
22
- require 'blur/network/user'
23
- require 'blur/network/channel'
24
- require 'blur/network/command'
25
- require 'blur/network/isupport'
26
- require 'blur/network/connection'
27
- require 'blur/script/commands'
14
+ require_relative './blur/version'
15
+ require_relative './blur/callbacks'
16
+ require_relative './blur/script'
17
+ require_relative './blur/script_cache'
18
+ require_relative './blur/network'
19
+ require_relative './blur/client'
20
+ require_relative './blur/user'
21
+ require_relative './blur/channel'
22
+ require_relative './blur/network/isupport'
23
+ require_relative './blur/network/connection'
28
24
 
29
25
  # Blur is a very modular IRC-framework for ruby.
30
26
  #
31
27
  # It allows the developer to extend it in multiple ways.
32
28
  # It can be by handlers, scripts, communications, and what have you.
33
29
  module Blur
30
+ # Client error.
31
+ class ClientError < StandardError; end
32
+
33
+ # Configuration file error.
34
+ class ConfigError < StandardError; end
35
+
36
+ # Creates a new superscript class and inserts it into the list of scripts.
37
+ def self.Script name, *_args, &block
38
+ klass = Class.new SuperScript
39
+ klass.name = name
40
+ klass.events = {}
41
+ klass.class_exec &block
42
+ klass.init
43
+
44
+ scripts[name] = klass
45
+ end
46
+
47
+ # Gets all superscript classes.
48
+ def self.scripts
49
+ @scripts ||= {}
50
+ end
51
+
52
+ # Resets all scripts.
53
+ #
54
+ # This method will call `deinit` on each script class before removing them to
55
+ # give them a chance to clean up.
56
+ def self.reset_scripts!
57
+ scripts.each_value &:deinit
58
+ scripts.clear
59
+ end
60
+
34
61
  # Instantiates a client with given options and then makes the client instance
35
62
  # evaluate the given block to form a DSL.
36
63
  #
metadata CHANGED
@@ -1,77 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blur
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.6
4
+ version: 2.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikkel Kroman
8
- autorequire:
9
- bindir: bin
8
+ autorequire:
9
+ bindir: executables
10
10
  cert_chain: []
11
- date: 2016-01-11 00:00:00.000000000 Z
11
+ date: 2021-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: majic
14
+ name: deep_merge
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.4'
19
+ version: '1.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.4'
26
+ version: '1.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: eventmachine
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: '1.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.0'
41
- description:
40
+ version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ircparser
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
55
+ description:
42
56
  email: mk@uplink.io
43
- executables: []
57
+ executables:
58
+ - blur
44
59
  extensions: []
45
60
  extra_rdoc_files: []
46
61
  files:
47
62
  - ".yardopts"
48
63
  - LICENSE
49
64
  - README.md
65
+ - executables/blur
50
66
  - library/blur.rb
67
+ - library/blur/callbacks.rb
68
+ - library/blur/channel.rb
51
69
  - library/blur/client.rb
52
- - library/blur/encryption.rb
53
- - library/blur/encryption/base64.rb
54
- - library/blur/encryption/fish.rb
55
- - library/blur/enhancements.rb
56
- - library/blur/evaluable.rb
57
- - library/blur/extension.rb
58
70
  - library/blur/handling.rb
59
71
  - library/blur/network.rb
60
- - library/blur/network/channel.rb
61
- - library/blur/network/command.rb
62
72
  - library/blur/network/connection.rb
63
73
  - library/blur/network/isupport.rb
64
- - library/blur/network/user.rb
65
74
  - library/blur/script.rb
66
- - library/blur/script/cache.rb
67
- - library/blur/script/commands.rb
68
- - library/blur/script/dsl.rb
75
+ - library/blur/script_cache.rb
76
+ - library/blur/user.rb
69
77
  - library/blur/version.rb
70
78
  homepage: https://github.com/mkroman/blur
71
79
  licenses:
72
80
  - MIT
73
81
  metadata: {}
74
- post_install_message:
82
+ post_install_message:
75
83
  rdoc_options: []
76
84
  require_paths:
77
85
  - library
@@ -79,16 +87,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
87
  requirements:
80
88
  - - ">="
81
89
  - !ruby/object:Gem::Version
82
- version: 1.9.1
90
+ version: '2.7'
83
91
  required_rubygems_version: !ruby/object:Gem::Requirement
84
92
  requirements:
85
93
  - - ">="
86
94
  - !ruby/object:Gem::Version
87
95
  version: '0'
88
96
  requirements: []
89
- rubyforge_project:
90
- rubygems_version: 2.2.0
91
- signing_key:
97
+ rubygems_version: 3.1.4
98
+ signing_key:
92
99
  specification_version: 4
93
100
  summary: An event-driven IRC-framework for Ruby.
94
101
  test_files: []