fauna 1.3.4 → 2.0.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 +5 -13
- data/CHANGELOG +2 -0
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/README.md +65 -102
- data/Rakefile +12 -20
- data/fauna.gemspec +19 -44
- data/lib/fauna.rb +12 -14
- data/lib/fauna/client.rb +225 -27
- data/lib/fauna/client_logger.rb +52 -0
- data/lib/fauna/context.rb +135 -0
- data/lib/fauna/errors.rb +181 -0
- data/lib/fauna/json.rb +60 -0
- data/lib/fauna/objects.rb +96 -0
- data/lib/fauna/query.rb +601 -0
- data/lib/fauna/request_result.rb +58 -0
- data/lib/fauna/util.rb +41 -0
- data/lib/fauna/version.rb +4 -0
- data/spec/client_logger_spec.rb +73 -0
- data/spec/client_spec.rb +202 -0
- data/spec/context_spec.rb +121 -0
- data/spec/errors_spec.rb +144 -0
- data/spec/fauna_helper.rb +87 -0
- data/spec/json_spec.rb +123 -0
- data/spec/query_spec.rb +675 -0
- data/spec/ref_spec.rb +77 -0
- data/spec/setref_spec.rb +23 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/util_spec.rb +19 -0
- metadata +65 -83
- data/Manifest +0 -25
- data/lib/fauna/cache.rb +0 -64
- data/lib/fauna/connection.rb +0 -152
- data/lib/fauna/named_resource.rb +0 -17
- data/lib/fauna/rails.rb +0 -120
- data/lib/fauna/resource.rb +0 -175
- data/lib/fauna/set.rb +0 -240
- data/lib/tasks/fauna.rake +0 -71
- data/test/class_test.rb +0 -65
- data/test/client_test.rb +0 -63
- data/test/connection_test.rb +0 -66
- data/test/database_test.rb +0 -48
- data/test/query_test.rb +0 -48
- data/test/readme_test.rb +0 -30
- data/test/set_test.rb +0 -71
- data/test/test_helper.rb +0 -86
@@ -0,0 +1,52 @@
|
|
1
|
+
module Fauna
|
2
|
+
# Example observer that can be used for debugging
|
3
|
+
module ClientLogger
|
4
|
+
##
|
5
|
+
# Lambda that can be the +observer+ for a Client.
|
6
|
+
# Will call the passed block on a string representation of each RequestResult.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# logger = ClientLogger.logger do |str|
|
11
|
+
# puts str
|
12
|
+
# end
|
13
|
+
# Client.new observer: logger, ...
|
14
|
+
def self.logger
|
15
|
+
lambda do |request_result|
|
16
|
+
yield show_request_result(request_result)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Translates a RequestResult to a string suitable for logging.
|
21
|
+
def self.show_request_result(request_result)
|
22
|
+
rr = request_result
|
23
|
+
logged = ''
|
24
|
+
|
25
|
+
logged << "Fauna #{rr.method.to_s.upcase} /#{rr.path}#{query_string_for_logging(rr.query)}\n"
|
26
|
+
logged << " Credentials: #{rr.auth}\n"
|
27
|
+
if rr.request_content
|
28
|
+
logged << " Request JSON: #{indent(FaunaJson.to_json_pretty(rr.request_content))}\n"
|
29
|
+
end
|
30
|
+
logged << " Response headers: #{indent(FaunaJson.to_json_pretty(rr.response_headers))}\n"
|
31
|
+
logged << " Response JSON: #{indent(FaunaJson.to_json_pretty(rr.response_content))}\n"
|
32
|
+
logged << " Response (#{rr.status_code}): Network latency #{(rr.time_taken * 1000).to_i}ms"
|
33
|
+
|
34
|
+
logged
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.indent(str) # :nodoc:
|
38
|
+
indent_str = ' '
|
39
|
+
str.split("\n").join("\n" + indent_str)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.query_string_for_logging(query) # :nodoc:
|
43
|
+
return unless query && !query.empty?
|
44
|
+
|
45
|
+
'?' + query.collect do |k, v|
|
46
|
+
"#{k}=#{v}"
|
47
|
+
end.join('&')
|
48
|
+
end
|
49
|
+
|
50
|
+
private_class_method :indent, :query_string_for_logging
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Fauna
|
2
|
+
##
|
3
|
+
# Error raised when the context is used without a client being set.
|
4
|
+
class NoContextError < RuntimeError; end
|
5
|
+
|
6
|
+
##
|
7
|
+
# The client context wrapper.
|
8
|
+
#
|
9
|
+
# Used for accessing the client without directly passing around the client instance.
|
10
|
+
# Context is scoped to the current thread.
|
11
|
+
class Context
|
12
|
+
##
|
13
|
+
# Returns a context block with the given client.
|
14
|
+
#
|
15
|
+
# +client+:: Client to use for the context block.
|
16
|
+
def self.block(client)
|
17
|
+
push(client)
|
18
|
+
yield
|
19
|
+
ensure
|
20
|
+
pop
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Adds a client to the current context.
|
25
|
+
#
|
26
|
+
# +client+:: Client to add to the current context.
|
27
|
+
def self.push(client)
|
28
|
+
stack.push(client)
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Removes the last client context from the stack and returns it.
|
33
|
+
def self.pop
|
34
|
+
stack.pop
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Resets the current client context, removing all the clients from the stack.
|
39
|
+
def self.reset
|
40
|
+
stack.clear
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Performs a +GET+ request for a REST endpoint within the current client context.
|
45
|
+
#
|
46
|
+
# +path+:: Path to +GET+.
|
47
|
+
# +query+:: Query parameters to append to the path.
|
48
|
+
#
|
49
|
+
# Reference: {FaunaDB REST API}[https://faunadb.com/documentation/rest]
|
50
|
+
#
|
51
|
+
# :category: Client Methods
|
52
|
+
def self.get(path, query = {})
|
53
|
+
client.get(path, query)
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Performs a +POST+ request for a REST endpoint within the current client context.
|
58
|
+
#
|
59
|
+
# +path+:: Path to +POST+.
|
60
|
+
# +data+:: Data to post as the body.
|
61
|
+
#
|
62
|
+
# Reference: {FaunaDB REST API}[https://faunadb.com/documentation/rest]
|
63
|
+
#
|
64
|
+
# :category: Client Methods
|
65
|
+
def self.post(path, data = {})
|
66
|
+
client.post(path, data)
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Performs a +PUT+ request for a REST endpoint within the current client context.
|
71
|
+
#
|
72
|
+
# +path+:: Path to +PUT+.
|
73
|
+
# +data+:: Data to post as the body.
|
74
|
+
#
|
75
|
+
# Reference: {FaunaDB REST API}[https://faunadb.com/documentation/rest]
|
76
|
+
#
|
77
|
+
# :category: Client Methods
|
78
|
+
def self.put(path, data = {})
|
79
|
+
client.put(path, data)
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Performs a +PATCH+ request for a REST endpoint within the current client context.
|
84
|
+
#
|
85
|
+
# +path+:: Path to +PATCH+.
|
86
|
+
# +data+:: Data to post as the body.
|
87
|
+
#
|
88
|
+
# Reference: {FaunaDB REST API}[https://faunadb.com/documentation/rest]
|
89
|
+
#
|
90
|
+
# :category: Client Methods
|
91
|
+
def self.patch(path, data = {})
|
92
|
+
client.patch(path, data)
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# Performs a +DELETE+ request for a REST endpoint within the current client context.
|
97
|
+
#
|
98
|
+
# +path+:: Path to +DELETE+.
|
99
|
+
# +data+:: Data to post as the body.
|
100
|
+
#
|
101
|
+
# Reference: {FaunaDB REST API}[https://faunadb.com/documentation/rest]
|
102
|
+
#
|
103
|
+
# :category: Client Methods
|
104
|
+
def self.delete(path)
|
105
|
+
client.delete(path)
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# Issues a query to FaunaDB with the current client context.
|
110
|
+
#
|
111
|
+
# Queries are built via the Query helpers. See {FaunaDB Query API}[https://faunadb.com/documentation/queries]
|
112
|
+
# for information on constructing queries.
|
113
|
+
#
|
114
|
+
# +expression+:: A query expression
|
115
|
+
#
|
116
|
+
# :category: Client Methods
|
117
|
+
def self.query(expression = nil, &expr_block)
|
118
|
+
client.query(expression, &expr_block)
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Returns the current context's client, or if there is none, raises NoContextError.
|
123
|
+
def self.client
|
124
|
+
stack.last || fail(NoContextError, 'You must be within a Fauna::Context.block to perform operations.')
|
125
|
+
end
|
126
|
+
|
127
|
+
class << self
|
128
|
+
private
|
129
|
+
|
130
|
+
def stack
|
131
|
+
Thread.current[:fauna_context_stack] ||= []
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/fauna/errors.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
module Fauna
|
2
|
+
##
|
3
|
+
# Error for when the server returns an unexpected kind of response.
|
4
|
+
class UnexpectedError < RuntimeError
|
5
|
+
# RequestResult for the request that caused this error.
|
6
|
+
attr_reader :request_result
|
7
|
+
|
8
|
+
def initialize(description, request_result) # :nodoc:
|
9
|
+
super(description)
|
10
|
+
@request_result = request_result
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.get_or_raise(request_result, hash, key) # :nodoc:
|
14
|
+
unless hash.is_a? Hash and hash.key? key
|
15
|
+
fail UnexpectedError.new("Response JSON does not contain expected key #{key}", request_result)
|
16
|
+
end
|
17
|
+
hash[key]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Error returned by the FaunaDB server.
|
23
|
+
# For documentation of error types, see the docs[https://faunadb.com/documentation#errors].
|
24
|
+
class FaunaError < RuntimeError
|
25
|
+
# List of ErrorData objects returned by the server.
|
26
|
+
attr_reader :errors
|
27
|
+
|
28
|
+
# RequestResult for the request that caused this error.
|
29
|
+
attr_reader :request_result
|
30
|
+
|
31
|
+
##
|
32
|
+
# Raises the associated error from a RequestResult based on the status code.
|
33
|
+
#
|
34
|
+
# Returns +nil+ for 2xx status codes
|
35
|
+
def self.raise_for_status_code(request_result)
|
36
|
+
case request_result.status_code
|
37
|
+
when 200..299
|
38
|
+
|
39
|
+
when 400
|
40
|
+
fail BadRequest.new(request_result)
|
41
|
+
when 401
|
42
|
+
fail Unauthorized.new(request_result)
|
43
|
+
when 403
|
44
|
+
fail PermissionDenied.new(request_result)
|
45
|
+
when 404
|
46
|
+
fail NotFound.new(request_result)
|
47
|
+
when 405
|
48
|
+
fail MethodNotAllowed.new(request_result)
|
49
|
+
when 500
|
50
|
+
fail InternalError.new(request_result)
|
51
|
+
when 503
|
52
|
+
fail UnavailableError.new(request_result)
|
53
|
+
else
|
54
|
+
fail UnexpectedError.new('Unexpected status code.', request_result)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Creates a new error from a given RequestResult.
|
59
|
+
def initialize(request_result)
|
60
|
+
@request_result = request_result
|
61
|
+
errors_raw = UnexpectedError.get_or_raise request_result, request_result.response_content, :errors
|
62
|
+
@errors = catch :invalid_response do
|
63
|
+
throw :invalid_response unless errors_raw.is_a? Array
|
64
|
+
errors_raw.map { |error| ErrorData.from_hash(error) }
|
65
|
+
end
|
66
|
+
|
67
|
+
if @errors.nil?
|
68
|
+
fail UnexpectedError.new('Error data has an unexpected format.', request_result)
|
69
|
+
end
|
70
|
+
|
71
|
+
super(@errors ? @errors[0].description : '(empty `errors`)')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# An exception thrown if FaunaDB cannot evaluate a query.
|
76
|
+
class BadRequest < FaunaError; end
|
77
|
+
|
78
|
+
# An exception thrown if FaunaDB responds with an HTTP 401.
|
79
|
+
class Unauthorized < FaunaError; end
|
80
|
+
|
81
|
+
# An exception thrown if FaunaDB responds with an HTTP 403.
|
82
|
+
class PermissionDenied < FaunaError; end
|
83
|
+
|
84
|
+
# An exception thrown if FaunaDB responds with an HTTP 404 for non-query endpoints.
|
85
|
+
class NotFound < FaunaError; end
|
86
|
+
|
87
|
+
# An exception thrown if FaunaDB responds with an HTTP 405.
|
88
|
+
class MethodNotAllowed < FaunaError; end
|
89
|
+
|
90
|
+
##
|
91
|
+
# An exception thrown if FaunaDB responds with an HTTP 500. Such errors represent an internal
|
92
|
+
# failure within the database.
|
93
|
+
class InternalError < FaunaError; end
|
94
|
+
|
95
|
+
##
|
96
|
+
# An exception thrown if FaunaDB responds with an HTTP 503.
|
97
|
+
class UnavailableError < FaunaError; end
|
98
|
+
|
99
|
+
# Data for one error returned by the server.
|
100
|
+
class ErrorData
|
101
|
+
##
|
102
|
+
# Error code.
|
103
|
+
#
|
104
|
+
# Reference: {FaunaDB Error codes}[https://faunadb.com/documentation#errors]
|
105
|
+
attr_reader :code
|
106
|
+
# Error description.
|
107
|
+
attr_reader :description
|
108
|
+
# Position of the error in a query. May be +nil+.
|
109
|
+
attr_reader :position
|
110
|
+
# List of Failure objects returned by the server. +nil+ except for <code>validation failed</code> errors.
|
111
|
+
attr_reader :failures
|
112
|
+
|
113
|
+
def self.from_hash(hash) # :nodoc:
|
114
|
+
code = ErrorHelpers.get_or_throw hash, :code
|
115
|
+
description = ErrorHelpers.get_or_throw hash, :description
|
116
|
+
position = ErrorHelpers.map_position hash[:position]
|
117
|
+
failures = hash[:failures].map(&Failure.method(:from_hash)) unless hash[:failures].nil?
|
118
|
+
ErrorData.new code, description, position, failures
|
119
|
+
end
|
120
|
+
|
121
|
+
def initialize(code, description, position, failures) # :nodoc:
|
122
|
+
@code = code
|
123
|
+
@description = description
|
124
|
+
@position = position
|
125
|
+
@failures = failures
|
126
|
+
end
|
127
|
+
|
128
|
+
def inspect # :nodoc:
|
129
|
+
"ErrorData(#{code.inspect}, #{description.inspect}, #{position.inspect}, #{failures.inspect})"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Part of ErrorData.
|
135
|
+
# For more information, see the {docs}[https://faunadb.com/documentation#errors-invalid_data].
|
136
|
+
class Failure
|
137
|
+
# Failure code.
|
138
|
+
attr_reader :code
|
139
|
+
# Failure description.
|
140
|
+
attr_reader :description
|
141
|
+
# Field of the failure in the instance.
|
142
|
+
attr_reader :field
|
143
|
+
|
144
|
+
def self.from_hash(hash) # :nodoc:
|
145
|
+
Failure.new(
|
146
|
+
ErrorHelpers.get_or_throw(hash, :code),
|
147
|
+
ErrorHelpers.get_or_throw(hash, :description),
|
148
|
+
ErrorHelpers.map_position(hash[:field]),
|
149
|
+
)
|
150
|
+
end
|
151
|
+
|
152
|
+
def initialize(code, description, field) # :nodoc:
|
153
|
+
@code = code
|
154
|
+
@description = description
|
155
|
+
@field = field
|
156
|
+
end
|
157
|
+
|
158
|
+
def inspect # :nodoc:
|
159
|
+
"Failure(#{code.inspect}, #{description.inspect}, #{field.inspect})"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
module ErrorHelpers # :nodoc:
|
164
|
+
def self.map_position(position)
|
165
|
+
unless position.nil?
|
166
|
+
position.map do |part|
|
167
|
+
if part.is_a? String
|
168
|
+
part.to_sym
|
169
|
+
else
|
170
|
+
part
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.get_or_throw(hash, key)
|
177
|
+
throw :invalid_response unless hash.is_a? Hash and hash.key? key
|
178
|
+
hash[key]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
data/lib/fauna/json.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
module Fauna
|
2
|
+
module FaunaJson # :nodoc:
|
3
|
+
def self.to_json(value)
|
4
|
+
serialize(value).to_json
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.to_json_pretty(value)
|
8
|
+
JSON.pretty_generate serialize(value)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.deserialize(obj)
|
12
|
+
if obj.is_a?(Hash)
|
13
|
+
if obj.key? :@ref
|
14
|
+
Ref.new obj[:@ref]
|
15
|
+
elsif obj.key? :@set
|
16
|
+
SetRef.new deserialize(obj[:@set])
|
17
|
+
elsif obj.key? :@obj
|
18
|
+
deserialize(obj[:@obj])
|
19
|
+
elsif obj.key? :@ts
|
20
|
+
Time.iso8601 obj[:@ts]
|
21
|
+
elsif obj.key? :@date
|
22
|
+
Date.iso8601 obj[:@date]
|
23
|
+
else
|
24
|
+
Hash[obj.collect { |k, v| [k, deserialize(v)] }]
|
25
|
+
end
|
26
|
+
elsif obj.is_a?(Array)
|
27
|
+
obj.collect { |val| deserialize(val) }
|
28
|
+
else
|
29
|
+
obj
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.json_load(body)
|
34
|
+
JSON.load body, nil, max_nesting: false, symbolize_names: true
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.json_load_or_nil(body)
|
38
|
+
json_load body
|
39
|
+
rescue JSON::ParserError
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.serialize(value)
|
44
|
+
if value.is_a? Time
|
45
|
+
# 9 means: include nanoseconds in encoding
|
46
|
+
{ :@ts => value.iso8601(9) }
|
47
|
+
elsif value.is_a? Date
|
48
|
+
{ :@date => value.iso8601 }
|
49
|
+
elsif value.is_a? Hash
|
50
|
+
Hash[value.collect { |k, v| [k, serialize(v)] }]
|
51
|
+
elsif value.is_a? Array
|
52
|
+
value.collect { |val| serialize(val) }
|
53
|
+
elsif value.respond_to? :to_hash
|
54
|
+
serialize(value.to_hash)
|
55
|
+
else
|
56
|
+
value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Fauna
|
2
|
+
##
|
3
|
+
# A Ref.
|
4
|
+
#
|
5
|
+
# Reference: {FaunaDB Special Types}[https://faunadb.com/documentation/queries-values-special_types]
|
6
|
+
class Ref
|
7
|
+
# The raw ref string.
|
8
|
+
attr_accessor :value
|
9
|
+
|
10
|
+
##
|
11
|
+
# Creates a Ref object.
|
12
|
+
#
|
13
|
+
# :call-seq:
|
14
|
+
# Ref.new('databases/prydain')
|
15
|
+
# Ref.new('databases', 'prydain')
|
16
|
+
# Ref.new(Ref.new('databases'), 'prydain')
|
17
|
+
#
|
18
|
+
# +parts+: A string, or a list of strings/refs to be joined.
|
19
|
+
def initialize(*parts)
|
20
|
+
@value = parts.join '/'
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Gets the class part out of the Ref.
|
25
|
+
# This is done by removing ref.id().
|
26
|
+
# So <code>Fauna::Ref.new('a', 'b/c').to_class</code> will be
|
27
|
+
# <code>Fauna::Ref.new('a/b')</code>.
|
28
|
+
def to_class
|
29
|
+
parts = value.split '/'
|
30
|
+
if parts.length == 1
|
31
|
+
self
|
32
|
+
else
|
33
|
+
Fauna::Ref.new(*parts[0...-1])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Removes the class part of the ref, leaving only the id.
|
39
|
+
# This is everything after the last /.
|
40
|
+
def id
|
41
|
+
parts = value.split '/'
|
42
|
+
fail ArgumentError.new 'The Ref does not have an id.' if parts.length == 1
|
43
|
+
parts.last
|
44
|
+
end
|
45
|
+
|
46
|
+
# Converts the Ref to a string
|
47
|
+
def to_s
|
48
|
+
value
|
49
|
+
end
|
50
|
+
|
51
|
+
# Converts the Ref in Hash form.
|
52
|
+
def to_hash
|
53
|
+
{ :@ref => value }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns +true+ if +other+ is a Ref and contains the same value.
|
57
|
+
def ==(other)
|
58
|
+
return false unless other.is_a? Ref
|
59
|
+
value == other.value
|
60
|
+
end
|
61
|
+
|
62
|
+
alias_method :eql?, :==
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# A SetRef.
|
67
|
+
#
|
68
|
+
# Reference: {FaunaDB Special Types}[https://faunadb.com/documentation/queries-values-special_types]
|
69
|
+
class SetRef
|
70
|
+
# The raw set hash.
|
71
|
+
attr_accessor :value
|
72
|
+
|
73
|
+
##
|
74
|
+
# Creates a new SetRef with the given parameters.
|
75
|
+
#
|
76
|
+
# +params+:: Hash of parameters to build the SetRef with.
|
77
|
+
#
|
78
|
+
# Reference: {FaunaDB Special Types}[https://faunadb.com/documentation/queries-values-special_types]
|
79
|
+
def initialize(params = {})
|
80
|
+
self.value = params
|
81
|
+
end
|
82
|
+
|
83
|
+
# Converts the SetRef to Hash form.
|
84
|
+
def to_hash
|
85
|
+
{ :@set => value }
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns +true+ if +other+ is a SetRef and contains the same value.
|
89
|
+
def ==(other)
|
90
|
+
return false unless other.is_a? SetRef
|
91
|
+
value == other.value
|
92
|
+
end
|
93
|
+
|
94
|
+
alias_method :eql?, :==
|
95
|
+
end
|
96
|
+
end
|