net-imap 0.5.12 → 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 +2 -1
- data/lib/net/imap/command_data.rb +0 -68
- data/lib/net/imap/config/attr_inheritance.rb +14 -1
- data/lib/net/imap/config/attr_version_defaults.rb +93 -0
- data/lib/net/imap/config.rb +210 -122
- 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 +621 -311
- data/lib/net/imap/uidplus_data.rb +2 -63
- data/lib/net/imap.rb +17 -23
- data/net-imap.gemspec +1 -1
- metadata +4 -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
|
#
|
|
@@ -2675,6 +2672,7 @@ module Net
|
|
|
2675
2672
|
# # fetch should return quickly and allocate little memory
|
|
2676
2673
|
# results.size # => 0..500
|
|
2677
2674
|
# break if results.empty?
|
|
2675
|
+
# results.sort_by!(&:uid) # server may return results out of order
|
|
2678
2676
|
# next_uid_to_fetch = results.last.uid + 1
|
|
2679
2677
|
# process results
|
|
2680
2678
|
# end
|
|
@@ -2780,7 +2778,7 @@ module Net
|
|
|
2780
2778
|
#
|
|
2781
2779
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
2782
2780
|
# supported, the server's response should include a +COPYUID+ response code
|
|
2783
|
-
# with
|
|
2781
|
+
# with CopyUIDData. This will report the UIDVALIDITY of the destination
|
|
2784
2782
|
# mailbox, the UID set of the source messages, and the assigned UID set of
|
|
2785
2783
|
# the moved messages.
|
|
2786
2784
|
#
|
|
@@ -2821,7 +2819,7 @@ module Net
|
|
|
2821
2819
|
#
|
|
2822
2820
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
2823
2821
|
# supported, the server's response should include a +COPYUID+ response code
|
|
2824
|
-
# with
|
|
2822
|
+
# with CopyUIDData. This will report the UIDVALIDITY of the destination
|
|
2825
2823
|
# mailbox, the UID set of the source messages, and the assigned UID set of
|
|
2826
2824
|
# the moved messages.
|
|
2827
2825
|
#
|
|
@@ -3581,11 +3579,11 @@ module Net
|
|
|
3581
3579
|
end
|
|
3582
3580
|
|
|
3583
3581
|
def enforce_logindisabled?
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
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
|
|
3589
3587
|
end
|
|
3590
3588
|
|
|
3591
3589
|
def expunge_internal(...)
|
|
@@ -3781,11 +3779,8 @@ module Net
|
|
|
3781
3779
|
def build_ssl_ctx(ssl)
|
|
3782
3780
|
if ssl
|
|
3783
3781
|
params = (Hash.try_convert(ssl) || {}).freeze
|
|
3784
|
-
context = SSLContext.new
|
|
3782
|
+
context = OpenSSL::SSL::SSLContext.new
|
|
3785
3783
|
context.set_params(params)
|
|
3786
|
-
if defined?(VerifyCallbackProc)
|
|
3787
|
-
context.verify_callback = VerifyCallbackProc
|
|
3788
|
-
end
|
|
3789
3784
|
context.freeze
|
|
3790
3785
|
[params, context]
|
|
3791
3786
|
else
|
|
@@ -3797,12 +3792,12 @@ module Net
|
|
|
3797
3792
|
raise "SSL extension not installed" unless defined?(OpenSSL::SSL)
|
|
3798
3793
|
raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket)
|
|
3799
3794
|
raise "cannot start TLS without SSLContext" unless ssl_ctx
|
|
3800
|
-
@sock = SSLSocket.new(@sock, ssl_ctx)
|
|
3795
|
+
@sock = OpenSSL::SSL::SSLSocket.new(@sock, ssl_ctx)
|
|
3801
3796
|
@reader = ResponseReader.new(self, @sock)
|
|
3802
3797
|
@sock.sync_close = true
|
|
3803
3798
|
@sock.hostname = @host if @sock.respond_to? :hostname=
|
|
3804
3799
|
ssl_socket_connect(@sock, open_timeout)
|
|
3805
|
-
if ssl_ctx.verify_mode != VERIFY_NONE
|
|
3800
|
+
if ssl_ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
|
3806
3801
|
@sock.post_connection_check(@host)
|
|
3807
3802
|
@tls_verified = true
|
|
3808
3803
|
end
|
|
@@ -3866,7 +3861,6 @@ require_relative "imap/errors"
|
|
|
3866
3861
|
require_relative "imap/config"
|
|
3867
3862
|
require_relative "imap/command_data"
|
|
3868
3863
|
require_relative "imap/data_encoding"
|
|
3869
|
-
require_relative "imap/data_lite"
|
|
3870
3864
|
require_relative "imap/flags"
|
|
3871
3865
|
require_relative "imap/response_data"
|
|
3872
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
|
|
@@ -60,9 +60,9 @@ files:
|
|
|
60
60
|
- lib/net/imap/config/attr_accessors.rb
|
|
61
61
|
- lib/net/imap/config/attr_inheritance.rb
|
|
62
62
|
- lib/net/imap/config/attr_type_coercion.rb
|
|
63
|
+
- lib/net/imap/config/attr_version_defaults.rb
|
|
63
64
|
- lib/net/imap/connection_state.rb
|
|
64
65
|
- lib/net/imap/data_encoding.rb
|
|
65
|
-
- lib/net/imap/data_lite.rb
|
|
66
66
|
- lib/net/imap/deprecated_client_options.rb
|
|
67
67
|
- lib/net/imap/errors.rb
|
|
68
68
|
- lib/net/imap/esearch_result.rb
|
|
@@ -122,14 +122,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
122
122
|
requirements:
|
|
123
123
|
- - ">="
|
|
124
124
|
- !ruby/object:Gem::Version
|
|
125
|
-
version: 3.
|
|
125
|
+
version: 3.2.0
|
|
126
126
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
127
|
requirements:
|
|
128
128
|
- - ">="
|
|
129
129
|
- !ruby/object:Gem::Version
|
|
130
130
|
version: '0'
|
|
131
131
|
requirements: []
|
|
132
|
-
rubygems_version:
|
|
132
|
+
rubygems_version: 4.0.1
|
|
133
133
|
specification_version: 4
|
|
134
134
|
summary: Ruby client api for Internet Message Access Protocol
|
|
135
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:
|