ircinch 2.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 +7 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +298 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +23 -0
- data/README.md +195 -0
- data/Rakefile +14 -0
- data/docs/bot_options.md +454 -0
- data/docs/changes.md +541 -0
- data/docs/common_mistakes.md +60 -0
- data/docs/common_tasks.md +57 -0
- data/docs/encodings.md +69 -0
- data/docs/events.md +273 -0
- data/docs/getting_started.md +184 -0
- data/docs/logging.md +90 -0
- data/docs/migrating.md +267 -0
- data/docs/plugins.md +4 -0
- data/docs/readme.md +20 -0
- data/examples/basic/autovoice.rb +32 -0
- data/examples/basic/google.rb +35 -0
- data/examples/basic/hello.rb +14 -0
- data/examples/basic/join_part.rb +35 -0
- data/examples/basic/memo.rb +39 -0
- data/examples/basic/msg.rb +15 -0
- data/examples/basic/seen.rb +37 -0
- data/examples/basic/urban_dict.rb +36 -0
- data/examples/basic/url_shorten.rb +36 -0
- data/examples/plugins/autovoice.rb +37 -0
- data/examples/plugins/custom_prefix.rb +22 -0
- data/examples/plugins/dice_roll.rb +38 -0
- data/examples/plugins/google.rb +36 -0
- data/examples/plugins/hello.rb +21 -0
- data/examples/plugins/hooks.rb +34 -0
- data/examples/plugins/join_part.rb +41 -0
- data/examples/plugins/lambdas.rb +35 -0
- data/examples/plugins/last_nick.rb +24 -0
- data/examples/plugins/msg.rb +21 -0
- data/examples/plugins/multiple_matches.rb +32 -0
- data/examples/plugins/own_events.rb +37 -0
- data/examples/plugins/seen.rb +44 -0
- data/examples/plugins/timer.rb +22 -0
- data/examples/plugins/url_shorten.rb +34 -0
- data/ircinch.gemspec +43 -0
- data/lib/cinch/ban.rb +53 -0
- data/lib/cinch/bot.rb +476 -0
- data/lib/cinch/cached_list.rb +21 -0
- data/lib/cinch/callback.rb +22 -0
- data/lib/cinch/channel.rb +465 -0
- data/lib/cinch/channel_list.rb +31 -0
- data/lib/cinch/configuration/bot.rb +50 -0
- data/lib/cinch/configuration/dcc.rb +18 -0
- data/lib/cinch/configuration/plugins.rb +43 -0
- data/lib/cinch/configuration/sasl.rb +21 -0
- data/lib/cinch/configuration/ssl.rb +21 -0
- data/lib/cinch/configuration/timeouts.rb +16 -0
- data/lib/cinch/configuration.rb +75 -0
- data/lib/cinch/constants.rb +535 -0
- data/lib/cinch/dcc/dccable_object.rb +39 -0
- data/lib/cinch/dcc/incoming/send.rb +149 -0
- data/lib/cinch/dcc/incoming.rb +3 -0
- data/lib/cinch/dcc/outgoing/send.rb +123 -0
- data/lib/cinch/dcc/outgoing.rb +3 -0
- data/lib/cinch/dcc.rb +14 -0
- data/lib/cinch/exceptions.rb +48 -0
- data/lib/cinch/formatting.rb +127 -0
- data/lib/cinch/handler.rb +120 -0
- data/lib/cinch/handler_list.rb +92 -0
- data/lib/cinch/helpers.rb +230 -0
- data/lib/cinch/i_support.rb +100 -0
- data/lib/cinch/irc.rb +924 -0
- data/lib/cinch/log_filter.rb +23 -0
- data/lib/cinch/logger/formatted_logger.rb +100 -0
- data/lib/cinch/logger/zcbot_logger.rb +26 -0
- data/lib/cinch/logger.rb +171 -0
- data/lib/cinch/logger_list.rb +88 -0
- data/lib/cinch/mask.rb +69 -0
- data/lib/cinch/message.rb +397 -0
- data/lib/cinch/message_queue.rb +104 -0
- data/lib/cinch/mode_parser.rb +78 -0
- data/lib/cinch/network.rb +106 -0
- data/lib/cinch/open_ended_queue.rb +26 -0
- data/lib/cinch/pattern.rb +66 -0
- data/lib/cinch/plugin.rb +517 -0
- data/lib/cinch/plugin_list.rb +40 -0
- data/lib/cinch/rubyext/float.rb +5 -0
- data/lib/cinch/rubyext/module.rb +28 -0
- data/lib/cinch/rubyext/string.rb +35 -0
- data/lib/cinch/sasl/dh_blowfish.rb +73 -0
- data/lib/cinch/sasl/diffie_hellman.rb +50 -0
- data/lib/cinch/sasl/mechanism.rb +8 -0
- data/lib/cinch/sasl/plain.rb +29 -0
- data/lib/cinch/sasl.rb +36 -0
- data/lib/cinch/syncable.rb +83 -0
- data/lib/cinch/target.rb +199 -0
- data/lib/cinch/timer.rb +147 -0
- data/lib/cinch/user.rb +489 -0
- data/lib/cinch/user_list.rb +89 -0
- data/lib/cinch/utilities/deprecation.rb +18 -0
- data/lib/cinch/utilities/encoding.rb +39 -0
- data/lib/cinch/utilities/kernel.rb +15 -0
- data/lib/cinch/version.rb +6 -0
- data/lib/cinch.rb +7 -0
- data/lib/ircinch.rb +7 -0
- metadata +205 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cinch
|
4
|
+
# LogFilter describes an interface for filtering log messages before
|
5
|
+
# they're printed.
|
6
|
+
#
|
7
|
+
# @abstract
|
8
|
+
# @since 2.3.0
|
9
|
+
class LogFilter
|
10
|
+
# filter is called for each log message, except for exceptions. It
|
11
|
+
# returns a new string, which is the one that should be printed, or
|
12
|
+
# further filtered by other filters. Returning nil will drop the
|
13
|
+
# message.
|
14
|
+
#
|
15
|
+
# @param [String] message The message that is to be logged
|
16
|
+
# @param [:debug, :incoming, :outgoing, :info, :warn, :exception,
|
17
|
+
# :error, :fatal] event The kind of message
|
18
|
+
# @return [String, nil] The modified message, as it should be
|
19
|
+
# logged, or nil if the message shouldn't be logged at all
|
20
|
+
def filter(message, event)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../logger"
|
4
|
+
|
5
|
+
module Cinch
|
6
|
+
class Logger
|
7
|
+
# @version 2.0.0
|
8
|
+
class FormattedLogger < Logger
|
9
|
+
# @private
|
10
|
+
COLORS = {
|
11
|
+
reset: "\e[0m",
|
12
|
+
bold: "\e[1m",
|
13
|
+
red: "\e[31m",
|
14
|
+
green: "\e[32m",
|
15
|
+
yellow: "\e[33m",
|
16
|
+
blue: "\e[34m",
|
17
|
+
black: "\e[30m",
|
18
|
+
bg_white: "\e[47m"
|
19
|
+
}
|
20
|
+
|
21
|
+
# (see Logger#exception)
|
22
|
+
def exception(e)
|
23
|
+
lines = ["#{e.backtrace.first}: #{e.message} (#{e.class})"]
|
24
|
+
lines.concat e.backtrace[1..].map { |s| "\t" + s }
|
25
|
+
log(lines, :exception, :error)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def timestamp
|
31
|
+
Time.now.strftime("[%Y/%m/%d %H:%M:%S.%L]")
|
32
|
+
end
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
# @param [String] text text to colorize
|
36
|
+
# @param [Array<Symbol>] codes array of colors to apply
|
37
|
+
# @return [String] colorized string
|
38
|
+
def colorize(text, *codes)
|
39
|
+
return text unless @output.tty?
|
40
|
+
codes = COLORS.values_at(*codes).join
|
41
|
+
text = text.gsub(/#{Regexp.escape(COLORS[:reset])}/, COLORS[:reset] + codes)
|
42
|
+
codes + text + COLORS[:reset]
|
43
|
+
end
|
44
|
+
|
45
|
+
def format_general(message)
|
46
|
+
message.gsub(/[^[:print:]]/) do |m|
|
47
|
+
colorize(m.inspect[1..-2], :bg_white, :black)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def format_debug(message)
|
52
|
+
"%s %s %s" % [timestamp, colorize("!!", :yellow), message]
|
53
|
+
end
|
54
|
+
|
55
|
+
def format_warn(message)
|
56
|
+
format_debug(message)
|
57
|
+
end
|
58
|
+
|
59
|
+
def format_info(message)
|
60
|
+
"%s %s %s" % [timestamp, "II", message]
|
61
|
+
end
|
62
|
+
|
63
|
+
def format_incoming(message)
|
64
|
+
pre, msg = message.split(" :", 2)
|
65
|
+
pre_parts = pre.split(" ")
|
66
|
+
|
67
|
+
prefix = colorize(">>", :green)
|
68
|
+
|
69
|
+
if pre_parts.size == 1
|
70
|
+
pre_parts[0] = colorize(pre_parts[0], :bold)
|
71
|
+
else
|
72
|
+
pre_parts[0] = colorize(pre_parts[0], :blue)
|
73
|
+
pre_parts[1] = colorize(pre_parts[1], :bold)
|
74
|
+
end
|
75
|
+
|
76
|
+
"%s %s %s %s" % [timestamp,
|
77
|
+
prefix,
|
78
|
+
pre_parts.join(" "),
|
79
|
+
msg ? colorize(":#{msg}", :yellow) : ""]
|
80
|
+
end
|
81
|
+
|
82
|
+
def format_outgoing(message)
|
83
|
+
pre, msg = message.split(" :", 2)
|
84
|
+
pre_parts = pre.split(" ")
|
85
|
+
|
86
|
+
prefix = colorize("<<", :red)
|
87
|
+
pre_parts[0] = colorize(pre_parts[0], :bold)
|
88
|
+
|
89
|
+
"%s %s %s %s" % [timestamp,
|
90
|
+
prefix,
|
91
|
+
pre_parts.join(" "),
|
92
|
+
msg ? colorize(":#{msg}", :yellow) : ""]
|
93
|
+
end
|
94
|
+
|
95
|
+
def format_exception(message)
|
96
|
+
"%s %s %s" % [timestamp, colorize("!!", :red), message]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../logger"
|
4
|
+
|
5
|
+
module Cinch
|
6
|
+
class Logger
|
7
|
+
# This logger logs all incoming messages in the format of zcbot.
|
8
|
+
# All other debug output (outgoing messages, exceptions, ...) will
|
9
|
+
# silently be dropped. The sole purpose of this logger is to
|
10
|
+
# produce logs parseable by pisg (with the zcbot formatter) to
|
11
|
+
# create channel statistics..
|
12
|
+
class ZcbotLogger < Cinch::Logger
|
13
|
+
# (see Logger#log)
|
14
|
+
def log(messages, event, level = event)
|
15
|
+
return if event != :incoming
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def format_incoming(message)
|
22
|
+
Time.now.strftime("%m/%d/%Y %H:%M:%S ") + message
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/cinch/logger.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cinch
|
4
|
+
# This is the base logger class from which all loggers have to
|
5
|
+
# inherit.
|
6
|
+
#
|
7
|
+
# @version 2.0.0
|
8
|
+
class Logger
|
9
|
+
# @private
|
10
|
+
LEVEL_ORDER = [:debug, :log, :info, :warn, :error, :fatal]
|
11
|
+
|
12
|
+
# @return [Array<:debug, :log, :info, :warn, :error, :fatal>]
|
13
|
+
# The minimum level of events to log
|
14
|
+
attr_accessor :level
|
15
|
+
|
16
|
+
# @return [Mutex]
|
17
|
+
# @api private
|
18
|
+
attr_reader :mutex
|
19
|
+
|
20
|
+
# @return [IO]
|
21
|
+
# @api private
|
22
|
+
attr_reader :output
|
23
|
+
|
24
|
+
# @param [IO] output The I/O object to write log data to
|
25
|
+
def initialize(output, level: :debug)
|
26
|
+
@output = output
|
27
|
+
@mutex = Mutex.new
|
28
|
+
@level = level
|
29
|
+
end
|
30
|
+
|
31
|
+
# Logs a debugging message.
|
32
|
+
#
|
33
|
+
# @param [String] message
|
34
|
+
# @return [void]
|
35
|
+
# @version 2.0.0
|
36
|
+
def debug(message)
|
37
|
+
log(message, :debug)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Logs an error message.
|
41
|
+
#
|
42
|
+
# @param [String] message
|
43
|
+
# @return [void]
|
44
|
+
# @since 2.0.0
|
45
|
+
def error(message)
|
46
|
+
log(message, :error)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Logs a fatal message.
|
50
|
+
#
|
51
|
+
# @param [String] message
|
52
|
+
# @return [void]
|
53
|
+
# @since 2.0.0
|
54
|
+
def fatal(message)
|
55
|
+
log(message, :fatal)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Logs an info message.
|
59
|
+
#
|
60
|
+
# @param [String] message
|
61
|
+
# @return [void]
|
62
|
+
# @since 2.0.0
|
63
|
+
def info(message)
|
64
|
+
log(message, :info)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Logs a warning message.
|
68
|
+
#
|
69
|
+
# @param [String] message
|
70
|
+
# @return [void]
|
71
|
+
# @since 2.0.0
|
72
|
+
def warn(message)
|
73
|
+
log(message, :warn)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Logs an incoming IRC message.
|
77
|
+
#
|
78
|
+
# @param [String] message
|
79
|
+
# @return [void]
|
80
|
+
# @since 2.0.0
|
81
|
+
def incoming(message)
|
82
|
+
log(message, :incoming, :log)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Logs an outgoing IRC message.
|
86
|
+
#
|
87
|
+
# @param [String] message
|
88
|
+
# @return [void]
|
89
|
+
# @since 2.0.0
|
90
|
+
def outgoing(message)
|
91
|
+
log(message, :outgoing, :log)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Logs an exception.
|
95
|
+
#
|
96
|
+
# @param [Exception] e
|
97
|
+
# @return [void]
|
98
|
+
# @since 2.0.0
|
99
|
+
def exception(e)
|
100
|
+
log(e.message, :exception, :error)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Logs a message.
|
104
|
+
#
|
105
|
+
# @param [String, Array] messages The message(s) to log
|
106
|
+
# @param [:debug, :incoming, :outgoing, :info, :warn,
|
107
|
+
# :exception, :error, :fatal] event The kind of event that
|
108
|
+
# triggered the message
|
109
|
+
# @param [:debug, :info, :warn, :error, :fatal] level The level of the message
|
110
|
+
# @return [void]
|
111
|
+
# @version 2.0.0
|
112
|
+
def log(messages, event = :debug, level = event)
|
113
|
+
return unless will_log?(level)
|
114
|
+
@mutex.synchronize do
|
115
|
+
Array(messages).each do |message|
|
116
|
+
message = format_general(message)
|
117
|
+
message = format_message(message, event)
|
118
|
+
|
119
|
+
next if message.nil?
|
120
|
+
@output.puts message.encode("locale", invalid: :replace, undef: :replace)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# @param [:debug, :info, :warn, :error, :fatal] level
|
126
|
+
# @return [Boolean] Whether the currently set logging level will
|
127
|
+
# allow the passed in level to be logged
|
128
|
+
# @since 2.0.0
|
129
|
+
def will_log?(level)
|
130
|
+
LEVEL_ORDER.index(level) >= LEVEL_ORDER.index(@level)
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def format_message(message, level)
|
136
|
+
__send__ "format_#{level}", message
|
137
|
+
end
|
138
|
+
|
139
|
+
def format_general(message)
|
140
|
+
message
|
141
|
+
end
|
142
|
+
|
143
|
+
def format_debug(message)
|
144
|
+
message
|
145
|
+
end
|
146
|
+
|
147
|
+
def format_error(message)
|
148
|
+
message
|
149
|
+
end
|
150
|
+
|
151
|
+
def format_info(message)
|
152
|
+
message
|
153
|
+
end
|
154
|
+
|
155
|
+
def format_warn(message)
|
156
|
+
message
|
157
|
+
end
|
158
|
+
|
159
|
+
def format_incoming(message)
|
160
|
+
message
|
161
|
+
end
|
162
|
+
|
163
|
+
def format_outgoing(message)
|
164
|
+
message
|
165
|
+
end
|
166
|
+
|
167
|
+
def format_exception(message)
|
168
|
+
message
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cinch
|
4
|
+
# This class allows Cinch to use multiple loggers at once. A common
|
5
|
+
# use-case would be to log formatted messages to STDERR and a
|
6
|
+
# pisg-compatible log to a file.
|
7
|
+
#
|
8
|
+
# It inherits directly from Array, so adding new loggers is as easy
|
9
|
+
# as calling LoggerList#push.
|
10
|
+
#
|
11
|
+
# @attr_writer level
|
12
|
+
# @since 2.0.0
|
13
|
+
class LoggerList < Array
|
14
|
+
# A list of log filters that will be applied before emitting a log
|
15
|
+
# message.
|
16
|
+
#
|
17
|
+
# @return [Array<LogFilter>]
|
18
|
+
# @since 2.3.0
|
19
|
+
attr_accessor :filters
|
20
|
+
def initialize(*args)
|
21
|
+
@filters = []
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
# (see Logger#level=)
|
26
|
+
def level=(level)
|
27
|
+
each { |l| l.level = level }
|
28
|
+
end
|
29
|
+
|
30
|
+
# (see Logger#log)
|
31
|
+
def log(messages, event = :debug, level = event)
|
32
|
+
messages = Array(messages).map { |m| filter(m, event) }.compact
|
33
|
+
each { |l| l.log(messages, event, level) }
|
34
|
+
end
|
35
|
+
|
36
|
+
# (see Logger#debug)
|
37
|
+
def debug(message)
|
38
|
+
(m = filter(message, :debug)) && each { |l| l.debug(m) }
|
39
|
+
end
|
40
|
+
|
41
|
+
# (see Logger#error)
|
42
|
+
def error(message)
|
43
|
+
(m = filter(message, :error)) && each { |l| l.error(m) }
|
44
|
+
end
|
45
|
+
|
46
|
+
# (see Logger#error)
|
47
|
+
def fatal(message)
|
48
|
+
(m = filter(message, :fatal)) && each { |l| l.fatal(m) }
|
49
|
+
end
|
50
|
+
|
51
|
+
# (see Logger#info)
|
52
|
+
def info(message)
|
53
|
+
(m = filter(message, :info)) && each { |l| l.info(m) }
|
54
|
+
end
|
55
|
+
|
56
|
+
# (see Logger#warn)
|
57
|
+
def warn(message)
|
58
|
+
(m = filter(message, :warn)) && each { |l| l.warn(m) }
|
59
|
+
end
|
60
|
+
|
61
|
+
# (see Logger#incoming)
|
62
|
+
def incoming(message)
|
63
|
+
(m = filter(message, :incoming)) && each { |l| l.incoming(m) }
|
64
|
+
end
|
65
|
+
|
66
|
+
# (see Logger#outgoing)
|
67
|
+
def outgoing(message)
|
68
|
+
(m = filter(message, :outgoing)) && each { |l| l.outgoing(m) }
|
69
|
+
end
|
70
|
+
|
71
|
+
# (see Logger#exception)
|
72
|
+
def exception(e)
|
73
|
+
each { |l| l.exception(e) }
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def filter(m, ev)
|
79
|
+
@filters.each do |f|
|
80
|
+
m = f.filter(m, ev)
|
81
|
+
if m.nil?
|
82
|
+
break
|
83
|
+
end
|
84
|
+
end
|
85
|
+
m
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/cinch/mask.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cinch
|
4
|
+
# This class represents masks, which are primarily used for bans.
|
5
|
+
class Mask
|
6
|
+
# @return [String]
|
7
|
+
attr_reader :nick
|
8
|
+
# @return [String]
|
9
|
+
attr_reader :user
|
10
|
+
# @return [String]
|
11
|
+
attr_reader :host
|
12
|
+
# @return [String]
|
13
|
+
attr_reader :mask
|
14
|
+
|
15
|
+
# @version 1.1.2
|
16
|
+
# @param [String] mask
|
17
|
+
def initialize(mask)
|
18
|
+
@mask = mask
|
19
|
+
@nick, @user, @host = mask.match(/(.+)!(.+)@(.+)/)[1..]
|
20
|
+
@regexp = Regexp.new("^" + Regexp.escape(mask).gsub("\\*", ".*").gsub("\\?", ".?") + "$")
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Boolean]
|
24
|
+
# @since 1.1.0
|
25
|
+
def ==(other)
|
26
|
+
other.respond_to?(:mask) && other.mask == @mask
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Boolean]
|
30
|
+
# @since 1.1.0
|
31
|
+
def eql?(other)
|
32
|
+
other.is_a?(self.class) && self == other
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Fixnum]
|
36
|
+
def hash
|
37
|
+
@mask.hash
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param [Mask, String, #mask] target
|
41
|
+
# @return [Boolean]
|
42
|
+
# @version 1.1.2
|
43
|
+
def match(target)
|
44
|
+
self.class.from(target).mask =~ @regexp
|
45
|
+
|
46
|
+
# TODO support CIDR (freenode)
|
47
|
+
end
|
48
|
+
alias_method :=~, :match
|
49
|
+
|
50
|
+
# @return [String]
|
51
|
+
def to_s
|
52
|
+
@mask.dup
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param [String, #mask] target
|
56
|
+
# @return [target] if already a Mask
|
57
|
+
# @return [Mask]
|
58
|
+
# @version 2.0.0
|
59
|
+
def self.from(target)
|
60
|
+
return target if target.is_a?(self)
|
61
|
+
|
62
|
+
if target.respond_to?(:mask)
|
63
|
+
target.mask
|
64
|
+
else
|
65
|
+
Mask.new(target.to_s)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|