net-imap 0.5.13 → 0.6.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 +4 -4
- data/Gemfile +1 -0
- data/lib/net/imap/command_data.rb +0 -68
- data/lib/net/imap/config/attr_inheritance.rb +14 -1
- data/lib/net/imap/config.rb +175 -35
- data/lib/net/imap/connection_state.rb +1 -1
- data/lib/net/imap/data_encoding.rb +77 -28
- data/lib/net/imap/esearch_result.rb +6 -0
- data/lib/net/imap/response_data.rb +2 -3
- data/lib/net/imap/response_parser.rb +8 -13
- data/lib/net/imap/search_result.rb +6 -0
- data/lib/net/imap/sequence_set.rb +622 -327
- data/lib/net/imap/uidplus_data.rb +2 -63
- data/lib/net/imap.rb +17 -24
- data/net-imap.gemspec +1 -1
- metadata +3 -4
- data/lib/net/imap/data_lite.rb +0 -226
|
@@ -3,69 +3,8 @@
|
|
|
3
3
|
module Net
|
|
4
4
|
class IMAP < Protocol
|
|
5
5
|
|
|
6
|
-
# *NOTE:* <em>UIDPlusData is deprecated and will be removed in the +0.6.0+
|
|
7
|
-
# release.</em> To use AppendUIDData and CopyUIDData before +0.6.0+, set
|
|
8
|
-
# Config#parser_use_deprecated_uidplus_data to +false+.
|
|
9
|
-
#
|
|
10
|
-
# UIDPlusData represents the ResponseCode#data that accompanies the
|
|
11
|
-
# +APPENDUID+ and +COPYUID+ {response codes}[rdoc-ref:ResponseCode].
|
|
12
|
-
#
|
|
13
|
-
# A server that supports +UIDPLUS+ should send UIDPlusData in response to
|
|
14
|
-
# the append[rdoc-ref:Net::IMAP#append], copy[rdoc-ref:Net::IMAP#copy],
|
|
15
|
-
# move[rdoc-ref:Net::IMAP#move], {uid copy}[rdoc-ref:Net::IMAP#uid_copy],
|
|
16
|
-
# and {uid move}[rdoc-ref:Net::IMAP#uid_move] commands---unless the
|
|
17
|
-
# destination mailbox reports +UIDNOTSTICKY+.
|
|
18
|
-
#
|
|
19
|
-
# Note that append[rdoc-ref:Net::IMAP#append], copy[rdoc-ref:Net::IMAP#copy]
|
|
20
|
-
# and {uid_copy}[rdoc-ref:Net::IMAP#uid_copy] return UIDPlusData in their
|
|
21
|
-
# TaggedResponse. But move[rdoc-ref:Net::IMAP#copy] and
|
|
22
|
-
# {uid_move}[rdoc-ref:Net::IMAP#uid_move] _should_ send UIDPlusData in an
|
|
23
|
-
# UntaggedResponse response before sending their TaggedResponse. However
|
|
24
|
-
# some servers do send UIDPlusData in the TaggedResponse for +MOVE+
|
|
25
|
-
# commands---this complies with the older +UIDPLUS+ specification but is
|
|
26
|
-
# discouraged by the +MOVE+ extension and disallowed by +IMAP4rev2+.
|
|
27
|
-
#
|
|
28
|
-
# == Required capability
|
|
29
|
-
# Requires either +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315]]
|
|
30
|
-
# or +IMAP4rev2+ capability.
|
|
31
|
-
#
|
|
32
|
-
class UIDPlusData < Struct.new(:uidvalidity, :source_uids, :assigned_uids)
|
|
33
|
-
##
|
|
34
|
-
# method: uidvalidity
|
|
35
|
-
# :call-seq: uidvalidity -> nonzero uint32
|
|
36
|
-
#
|
|
37
|
-
# The UIDVALIDITY of the destination mailbox.
|
|
38
|
-
|
|
39
|
-
##
|
|
40
|
-
# method: source_uids
|
|
41
|
-
# :call-seq: source_uids -> nil or an array of nonzero uint32
|
|
42
|
-
#
|
|
43
|
-
# The UIDs of the copied or moved messages.
|
|
44
|
-
#
|
|
45
|
-
# Note:: Returns +nil+ for Net::IMAP#append.
|
|
46
|
-
|
|
47
|
-
##
|
|
48
|
-
# method: assigned_uids
|
|
49
|
-
# :call-seq: assigned_uids -> an array of nonzero uint32
|
|
50
|
-
#
|
|
51
|
-
# The newly assigned UIDs of the copied, moved, or appended messages.
|
|
52
|
-
#
|
|
53
|
-
# Note:: This always returns an array, even when it contains only one UID.
|
|
54
|
-
|
|
55
|
-
##
|
|
56
|
-
# :call-seq: uid_mapping -> nil or a hash
|
|
57
|
-
#
|
|
58
|
-
# Returns a hash mapping each source UID to the newly assigned destination
|
|
59
|
-
# UID.
|
|
60
|
-
#
|
|
61
|
-
# Note:: Returns +nil+ for Net::IMAP#append.
|
|
62
|
-
def uid_mapping
|
|
63
|
-
source_uids&.zip(assigned_uids)&.to_h
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
6
|
# >>>
|
|
68
|
-
# *NOTE:* <em>AppendUIDData
|
|
7
|
+
# *NOTE:* <em>AppendUIDData replaced UIDPlusData for +APPENDUID+ in the
|
|
69
8
|
# +0.6.0+ release.</em> To use AppendUIDData before +0.6.0+, set
|
|
70
9
|
# Config#parser_use_deprecated_uidplus_data to +false+.
|
|
71
10
|
#
|
|
@@ -109,7 +48,7 @@ module Net
|
|
|
109
48
|
end
|
|
110
49
|
|
|
111
50
|
# >>>
|
|
112
|
-
# *NOTE:* <em>CopyUIDData
|
|
51
|
+
# *NOTE:* <em>CopyUIDData replaced UIDPlusData for +COPYUID+ in the
|
|
113
52
|
# +0.6.0+ release.</em> To use CopyUIDData before +0.6.0+, set
|
|
114
53
|
# Config#parser_use_deprecated_uidplus_data to +false+.
|
|
115
54
|
#
|
data/lib/net/imap.rb
CHANGED
|
@@ -359,8 +359,8 @@ module Net
|
|
|
359
359
|
#
|
|
360
360
|
# - #capability: Returns the server's capabilities as an array of strings.
|
|
361
361
|
#
|
|
362
|
-
# <em>In general
|
|
363
|
-
# +CAPABILITY+ command to the server.</em>
|
|
362
|
+
# <em>In general,</em> #capable? <em>should be used rather than explicitly
|
|
363
|
+
# sending a +CAPABILITY+ command to the server.</em>
|
|
364
364
|
# - #noop: Allows the server to send unsolicited untagged #responses.
|
|
365
365
|
# - #logout: Tells the server to end the session. Enters the +logout+ state.
|
|
366
366
|
#
|
|
@@ -788,7 +788,7 @@ module Net
|
|
|
788
788
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
|
789
789
|
#
|
|
790
790
|
class IMAP < Protocol
|
|
791
|
-
VERSION = "0.
|
|
791
|
+
VERSION = "0.6.0"
|
|
792
792
|
|
|
793
793
|
# Aliases for supported capabilities, to be used with the #enable command.
|
|
794
794
|
ENABLE_ALIASES = {
|
|
@@ -805,10 +805,6 @@ module Net
|
|
|
805
805
|
autoload :StringPrep, "#{dir}/stringprep"
|
|
806
806
|
|
|
807
807
|
include MonitorMixin
|
|
808
|
-
if defined?(OpenSSL::SSL)
|
|
809
|
-
include OpenSSL
|
|
810
|
-
include SSL
|
|
811
|
-
end
|
|
812
808
|
|
|
813
809
|
# :call-seq:
|
|
814
810
|
# Net::IMAP::SequenceSet(set = nil) -> SequenceSet
|
|
@@ -1522,6 +1518,7 @@ module Net
|
|
|
1522
1518
|
# completes. If the TaggedResponse to #authenticate includes updated
|
|
1523
1519
|
# capabilities, they will be cached.
|
|
1524
1520
|
def authenticate(*args, sasl_ir: config.sasl_ir, **props, &callback)
|
|
1521
|
+
sasl_ir = may_depend_on_capabilities_cached?(sasl_ir)
|
|
1525
1522
|
sasl_adapter.authenticate(*args, sasl_ir: sasl_ir, **props, &callback)
|
|
1526
1523
|
.tap do state_authenticated! _1 end
|
|
1527
1524
|
end
|
|
@@ -1573,7 +1570,7 @@ module Net
|
|
|
1573
1570
|
# When the +condstore+ keyword argument is true, the server is told to
|
|
1574
1571
|
# enable the extension. If +mailbox+ supports persistence of mod-sequences,
|
|
1575
1572
|
# the +HIGHESTMODSEQ+ ResponseCode will be sent as an untagged response to
|
|
1576
|
-
# #select and all
|
|
1573
|
+
# #select and all +FETCH+ responses will include FetchData#modseq.
|
|
1577
1574
|
# Otherwise, the +NOMODSEQ+ ResponseCode will be sent.
|
|
1578
1575
|
#
|
|
1579
1576
|
# A Net::IMAP::NoResponseError is raised if the mailbox does not
|
|
@@ -2024,7 +2021,7 @@ module Net
|
|
|
2024
2021
|
#
|
|
2025
2022
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
2026
2023
|
# supported and the destination supports persistent UIDs, the server's
|
|
2027
|
-
# response should include an +APPENDUID+ response code with
|
|
2024
|
+
# response should include an +APPENDUID+ response code with AppendUIDData.
|
|
2028
2025
|
# This will report the UIDVALIDITY of the destination mailbox and the
|
|
2029
2026
|
# assigned UID of the appended message.
|
|
2030
2027
|
#
|
|
@@ -2781,7 +2778,7 @@ module Net
|
|
|
2781
2778
|
#
|
|
2782
2779
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
2783
2780
|
# supported, the server's response should include a +COPYUID+ response code
|
|
2784
|
-
# with
|
|
2781
|
+
# with CopyUIDData. This will report the UIDVALIDITY of the destination
|
|
2785
2782
|
# mailbox, the UID set of the source messages, and the assigned UID set of
|
|
2786
2783
|
# the moved messages.
|
|
2787
2784
|
#
|
|
@@ -2822,7 +2819,7 @@ module Net
|
|
|
2822
2819
|
#
|
|
2823
2820
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
2824
2821
|
# supported, the server's response should include a +COPYUID+ response code
|
|
2825
|
-
# with
|
|
2822
|
+
# with CopyUIDData. This will report the UIDVALIDITY of the destination
|
|
2826
2823
|
# mailbox, the UID set of the source messages, and the assigned UID set of
|
|
2827
2824
|
# the moved messages.
|
|
2828
2825
|
#
|
|
@@ -3233,7 +3230,7 @@ module Net
|
|
|
3233
3230
|
warn(RESPONSES_DEPRECATION_MSG, uplevel: 1, category: :deprecated)
|
|
3234
3231
|
when :frozen_dup
|
|
3235
3232
|
synchronize {
|
|
3236
|
-
responses = @responses.transform_values
|
|
3233
|
+
responses = @responses.transform_values(&:freeze)
|
|
3237
3234
|
responses.default_proc = nil
|
|
3238
3235
|
responses.default = [].freeze
|
|
3239
3236
|
return responses.freeze
|
|
@@ -3582,11 +3579,11 @@ module Net
|
|
|
3582
3579
|
end
|
|
3583
3580
|
|
|
3584
3581
|
def enforce_logindisabled?
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3582
|
+
may_depend_on_capabilities_cached?(config.enforce_logindisabled)
|
|
3583
|
+
end
|
|
3584
|
+
|
|
3585
|
+
def may_depend_on_capabilities_cached?(value)
|
|
3586
|
+
value == :when_capabilities_cached ? capabilities_cached? : value
|
|
3590
3587
|
end
|
|
3591
3588
|
|
|
3592
3589
|
def expunge_internal(...)
|
|
@@ -3782,11 +3779,8 @@ module Net
|
|
|
3782
3779
|
def build_ssl_ctx(ssl)
|
|
3783
3780
|
if ssl
|
|
3784
3781
|
params = (Hash.try_convert(ssl) || {}).freeze
|
|
3785
|
-
context = SSLContext.new
|
|
3782
|
+
context = OpenSSL::SSL::SSLContext.new
|
|
3786
3783
|
context.set_params(params)
|
|
3787
|
-
if defined?(VerifyCallbackProc)
|
|
3788
|
-
context.verify_callback = VerifyCallbackProc
|
|
3789
|
-
end
|
|
3790
3784
|
context.freeze
|
|
3791
3785
|
[params, context]
|
|
3792
3786
|
else
|
|
@@ -3798,12 +3792,12 @@ module Net
|
|
|
3798
3792
|
raise "SSL extension not installed" unless defined?(OpenSSL::SSL)
|
|
3799
3793
|
raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket)
|
|
3800
3794
|
raise "cannot start TLS without SSLContext" unless ssl_ctx
|
|
3801
|
-
@sock = SSLSocket.new(@sock, ssl_ctx)
|
|
3795
|
+
@sock = OpenSSL::SSL::SSLSocket.new(@sock, ssl_ctx)
|
|
3802
3796
|
@reader = ResponseReader.new(self, @sock)
|
|
3803
3797
|
@sock.sync_close = true
|
|
3804
3798
|
@sock.hostname = @host if @sock.respond_to? :hostname=
|
|
3805
3799
|
ssl_socket_connect(@sock, open_timeout)
|
|
3806
|
-
if ssl_ctx.verify_mode != VERIFY_NONE
|
|
3800
|
+
if ssl_ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
|
3807
3801
|
@sock.post_connection_check(@host)
|
|
3808
3802
|
@tls_verified = true
|
|
3809
3803
|
end
|
|
@@ -3867,7 +3861,6 @@ require_relative "imap/errors"
|
|
|
3867
3861
|
require_relative "imap/config"
|
|
3868
3862
|
require_relative "imap/command_data"
|
|
3869
3863
|
require_relative "imap/data_encoding"
|
|
3870
|
-
require_relative "imap/data_lite"
|
|
3871
3864
|
require_relative "imap/flags"
|
|
3872
3865
|
require_relative "imap/response_data"
|
|
3873
3866
|
require_relative "imap/response_parser"
|
data/net-imap.gemspec
CHANGED
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
|
|
|
16
16
|
spec.summary = %q{Ruby client api for Internet Message Access Protocol}
|
|
17
17
|
spec.description = %q{Ruby client api for Internet Message Access Protocol}
|
|
18
18
|
spec.homepage = "https://github.com/ruby/net-imap"
|
|
19
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 3.
|
|
19
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.2.0")
|
|
20
20
|
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
|
21
21
|
|
|
22
22
|
spec.metadata["homepage_uri"] = spec.homepage
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: net-imap
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shugo Maeda
|
|
@@ -63,7 +63,6 @@ files:
|
|
|
63
63
|
- lib/net/imap/config/attr_version_defaults.rb
|
|
64
64
|
- lib/net/imap/connection_state.rb
|
|
65
65
|
- lib/net/imap/data_encoding.rb
|
|
66
|
-
- lib/net/imap/data_lite.rb
|
|
67
66
|
- lib/net/imap/deprecated_client_options.rb
|
|
68
67
|
- lib/net/imap/errors.rb
|
|
69
68
|
- lib/net/imap/esearch_result.rb
|
|
@@ -123,14 +122,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
123
122
|
requirements:
|
|
124
123
|
- - ">="
|
|
125
124
|
- !ruby/object:Gem::Version
|
|
126
|
-
version: 3.
|
|
125
|
+
version: 3.2.0
|
|
127
126
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
127
|
requirements:
|
|
129
128
|
- - ">="
|
|
130
129
|
- !ruby/object:Gem::Version
|
|
131
130
|
version: '0'
|
|
132
131
|
requirements: []
|
|
133
|
-
rubygems_version:
|
|
132
|
+
rubygems_version: 4.0.1
|
|
134
133
|
specification_version: 4
|
|
135
134
|
summary: Ruby client api for Internet Message Access Protocol
|
|
136
135
|
test_files: []
|
data/lib/net/imap/data_lite.rb
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Some of the code in this file was copied from the polyfill-data gem.
|
|
4
|
-
#
|
|
5
|
-
# MIT License
|
|
6
|
-
#
|
|
7
|
-
# Copyright (c) 2023 Jim Gay, Joel Drapper, Nicholas Evans
|
|
8
|
-
#
|
|
9
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
-
# of this software and associated documentation files (the "Software"), to deal
|
|
11
|
-
# in the Software without restriction, including without limitation the rights
|
|
12
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
14
|
-
# furnished to do so, subject to the following conditions:
|
|
15
|
-
#
|
|
16
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
17
|
-
# copies or substantial portions of the Software.
|
|
18
|
-
#
|
|
19
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
-
# SOFTWARE.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
module Net
|
|
29
|
-
class IMAP
|
|
30
|
-
data_or_object = RUBY_VERSION >= "3.2.0" ? ::Data : Object
|
|
31
|
-
class DataLite < data_or_object
|
|
32
|
-
def encode_with(coder) coder.map = to_h.transform_keys(&:to_s) end
|
|
33
|
-
def init_with(coder) initialize(**coder.map.transform_keys(&:to_sym)) end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
Data = DataLite
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# :nocov:
|
|
41
|
-
# Need to skip test coverage for the rest, because it isn't loaded by ruby 3.2+.
|
|
42
|
-
return if RUBY_VERSION >= "3.2.0"
|
|
43
|
-
|
|
44
|
-
module Net
|
|
45
|
-
class IMAP
|
|
46
|
-
# DataLite is a temporary substitute for ruby 3.2's +Data+ class. DataLite
|
|
47
|
-
# is aliased as Net::IMAP::Data, so that code using it won't need to be
|
|
48
|
-
# updated when it is removed.
|
|
49
|
-
#
|
|
50
|
-
# See {ruby 3.2's documentation for Data}[https://docs.ruby-lang.org/en/3.2/Data.html].
|
|
51
|
-
#
|
|
52
|
-
# [When running ruby 3.1]
|
|
53
|
-
# This class reimplements the API for ruby 3.2's +Data+, and should be
|
|
54
|
-
# compatible for nearly all use-cases. This reimplementation <em>will be
|
|
55
|
-
# removed</em> in +net-imap+ 0.6, when support for ruby 3.1 is dropped.
|
|
56
|
-
#
|
|
57
|
-
# _NOTE:_ +net-imap+ no longer supports ruby versions prior to 3.1.
|
|
58
|
-
# [When running ruby >= 3.2]
|
|
59
|
-
# This class inherits from +Data+ and _only_ defines the methods needed
|
|
60
|
-
# for YAML serialization. This will be dropped when +psych+ adds support
|
|
61
|
-
# for +Data+.
|
|
62
|
-
#
|
|
63
|
-
# Some of the code in this class was copied or adapted from the
|
|
64
|
-
# {polyfill-data gem}[https://rubygems.org/gems/polyfill-data], by Jim Gay
|
|
65
|
-
# and Joel Drapper, under the MIT license terms.
|
|
66
|
-
class DataLite
|
|
67
|
-
singleton_class.undef_method :new
|
|
68
|
-
|
|
69
|
-
TYPE_ERROR = "%p is not a symbol nor a string"
|
|
70
|
-
ATTRSET_ERROR = "invalid data member: %p"
|
|
71
|
-
DUP_ERROR = "duplicate member: %p"
|
|
72
|
-
ARITY_ERROR = "wrong number of arguments (given %d, expected %s)"
|
|
73
|
-
private_constant :TYPE_ERROR, :ATTRSET_ERROR, :DUP_ERROR, :ARITY_ERROR
|
|
74
|
-
|
|
75
|
-
# Defines a new Data class.
|
|
76
|
-
#
|
|
77
|
-
# _NOTE:_ Unlike ruby 3.2's +Data.define+, DataLite.define only supports
|
|
78
|
-
# member names which are valid local variable names. Member names can't
|
|
79
|
-
# be keywords (e.g: +next+ or +class+) or start with capital letters, "@",
|
|
80
|
-
# etc.
|
|
81
|
-
def self.define(*args, &block)
|
|
82
|
-
members = args.each_with_object({}) do |arg, members|
|
|
83
|
-
arg = arg.to_str unless arg in Symbol | String if arg.respond_to?(:to_str)
|
|
84
|
-
arg = arg.to_sym if arg in String
|
|
85
|
-
arg in Symbol or raise TypeError, TYPE_ERROR % [arg]
|
|
86
|
-
arg in %r{=} and raise ArgumentError, ATTRSET_ERROR % [arg]
|
|
87
|
-
members.key?(arg) and raise ArgumentError, DUP_ERROR % [arg]
|
|
88
|
-
members[arg] = true
|
|
89
|
-
end
|
|
90
|
-
members = members.keys.freeze
|
|
91
|
-
|
|
92
|
-
klass = ::Class.new(self)
|
|
93
|
-
|
|
94
|
-
klass.singleton_class.undef_method :define
|
|
95
|
-
klass.define_singleton_method(:members) { members }
|
|
96
|
-
|
|
97
|
-
def klass.new(*args, **kwargs, &block)
|
|
98
|
-
if kwargs.size.positive?
|
|
99
|
-
if args.size.positive?
|
|
100
|
-
raise ArgumentError, ARITY_ERROR % [args.size, 0]
|
|
101
|
-
end
|
|
102
|
-
elsif members.size < args.size
|
|
103
|
-
expected = members.size.zero? ? 0 : 0..members.size
|
|
104
|
-
raise ArgumentError, ARITY_ERROR % [args.size, expected]
|
|
105
|
-
else
|
|
106
|
-
kwargs = Hash[members.take(args.size).zip(args)]
|
|
107
|
-
end
|
|
108
|
-
allocate.tap do |instance|
|
|
109
|
-
instance.__send__(:initialize, **kwargs, &block)
|
|
110
|
-
end.freeze
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
klass.singleton_class.alias_method :[], :new
|
|
114
|
-
klass.attr_reader(*members)
|
|
115
|
-
|
|
116
|
-
# Dynamically defined initializer methods are in an included module,
|
|
117
|
-
# rather than directly on DataLite (like in ruby 3.2+):
|
|
118
|
-
# * simpler to handle required kwarg ArgumentErrors
|
|
119
|
-
# * easier to ensure consistent ivar assignment order (object shape)
|
|
120
|
-
# * faster than instance_variable_set
|
|
121
|
-
klass.include(Module.new do
|
|
122
|
-
if members.any?
|
|
123
|
-
kwargs = members.map{"#{_1.name}:"}.join(", ")
|
|
124
|
-
params = members.map(&:name).join(", ")
|
|
125
|
-
ivars = members.map{"@#{_1.name}"}.join(", ")
|
|
126
|
-
attrs = members.map{"attrs[:#{_1.name}]"}.join(", ")
|
|
127
|
-
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
128
|
-
protected
|
|
129
|
-
def initialize(#{kwargs}) #{ivars} = #{params}; freeze end
|
|
130
|
-
def marshal_load(attrs) #{ivars} = #{attrs}; freeze end
|
|
131
|
-
RUBY
|
|
132
|
-
end
|
|
133
|
-
end)
|
|
134
|
-
|
|
135
|
-
klass.module_eval do _1.module_eval(&block) end if block_given?
|
|
136
|
-
|
|
137
|
-
klass
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
##
|
|
141
|
-
# singleton-method: new
|
|
142
|
-
# call-seq:
|
|
143
|
-
# new(*args) -> instance
|
|
144
|
-
# new(**kwargs) -> instance
|
|
145
|
-
#
|
|
146
|
-
# Constuctor for classes defined with ::define.
|
|
147
|
-
#
|
|
148
|
-
# Aliased as ::[].
|
|
149
|
-
|
|
150
|
-
##
|
|
151
|
-
# singleton-method: []
|
|
152
|
-
# call-seq:
|
|
153
|
-
# ::[](*args) -> instance
|
|
154
|
-
# ::[](**kwargs) -> instance
|
|
155
|
-
#
|
|
156
|
-
# Constuctor for classes defined with ::define.
|
|
157
|
-
#
|
|
158
|
-
# Alias for ::new
|
|
159
|
-
|
|
160
|
-
##
|
|
161
|
-
def members; self.class.members end
|
|
162
|
-
def to_h(&block) block ? __to_h__.to_h(&block) : __to_h__ end
|
|
163
|
-
def hash; [self.class, __to_h__].hash end
|
|
164
|
-
def ==(other) self.class == other.class && to_h == other.to_h end
|
|
165
|
-
def eql?(other) self.class == other.class && hash == other.hash end
|
|
166
|
-
def deconstruct; __to_h__.values end
|
|
167
|
-
|
|
168
|
-
def deconstruct_keys(keys)
|
|
169
|
-
raise TypeError unless keys.is_a?(Array) || keys.nil?
|
|
170
|
-
return __to_h__ if keys&.first.nil?
|
|
171
|
-
__to_h__.slice(*keys)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def with(**kwargs)
|
|
175
|
-
return self if kwargs.empty?
|
|
176
|
-
self.class.new(**__to_h__.merge(kwargs))
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def inspect
|
|
180
|
-
__inspect_guard__(self) do |seen|
|
|
181
|
-
return "#<data #{self.class}:...>" if seen
|
|
182
|
-
attrs = __to_h__.map {|kv| "%s=%p" % kv }.join(", ")
|
|
183
|
-
display = ["data", self.class.name, attrs].compact.join(" ")
|
|
184
|
-
"#<#{display}>"
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
alias_method :to_s, :inspect
|
|
188
|
-
|
|
189
|
-
private
|
|
190
|
-
|
|
191
|
-
def initialize_copy(source) super.freeze end
|
|
192
|
-
def marshal_dump; __to_h__ end
|
|
193
|
-
|
|
194
|
-
def __to_h__; Hash[members.map {|m| [m, send(m)] }] end
|
|
195
|
-
|
|
196
|
-
# Yields +true+ if +obj+ has been seen already, +false+ if it hasn't.
|
|
197
|
-
# Marks +obj+ as seen inside the block, so circuler references don't
|
|
198
|
-
# recursively trigger a SystemStackError (stack level too deep).
|
|
199
|
-
#
|
|
200
|
-
# Making circular references inside a Data object _should_ be very
|
|
201
|
-
# uncommon, but we'll support them for the sake of completeness.
|
|
202
|
-
def __inspect_guard__(obj)
|
|
203
|
-
preexisting = Thread.current[:__net_imap_data__inspect__]
|
|
204
|
-
Thread.current[:__net_imap_data__inspect__] ||= {}.compare_by_identity
|
|
205
|
-
inspect_guard = Thread.current[:__net_imap_data__inspect__]
|
|
206
|
-
if inspect_guard.include?(obj)
|
|
207
|
-
yield true
|
|
208
|
-
else
|
|
209
|
-
begin
|
|
210
|
-
inspect_guard[obj] = true
|
|
211
|
-
yield false
|
|
212
|
-
ensure
|
|
213
|
-
inspect_guard.delete(obj)
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
ensure
|
|
217
|
-
unless preexisting.equal?(inspect_guard)
|
|
218
|
-
Thread.current[:__net_imap_data__inspect__] = preexisting
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
# :nocov:
|