gmail 0.4.0 → 0.4.2
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/.gitignore +26 -25
- data/.rspec +2 -0
- data/CHANGELOG.md +82 -82
- data/Gemfile +3 -0
- data/LICENSE +21 -21
- data/README.md +271 -251
- data/Rakefile +35 -45
- data/TODO.md +12 -7
- data/gmail.gemspec +34 -23
- data/lib/gmail.rb +65 -82
- data/lib/gmail/client.rb +30 -22
- data/lib/gmail/client/base.rb +225 -220
- data/lib/gmail/client/imap_extensions.rb +54 -0
- data/lib/gmail/client/plain.rb +20 -18
- data/lib/gmail/client/xoauth.rb +51 -49
- data/lib/gmail/labels.rb +62 -48
- data/lib/gmail/mailbox.rb +117 -117
- data/lib/gmail/message.rb +166 -164
- data/lib/gmail/version.rb +3 -12
- data/spec/account.yml.example +1 -1
- data/spec/client_spec.rb +178 -173
- data/spec/gmail_spec.rb +39 -38
- data/spec/mailbox_spec.rb +47 -49
- data/spec/message_spec.rb +51 -51
- data/spec/spec_helper.rb +28 -28
- metadata +109 -110
data/lib/gmail/message.rb
CHANGED
@@ -1,164 +1,166 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
when :
|
36
|
-
when :
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
#
|
99
|
-
#
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
#
|
109
|
-
#
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
return true
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
1
|
+
module Gmail
|
2
|
+
class Message
|
3
|
+
# Raised when given label doesn't exists.
|
4
|
+
class NoLabelError < Exception; end
|
5
|
+
|
6
|
+
attr_reader :uid
|
7
|
+
|
8
|
+
def initialize(mailbox, uid)
|
9
|
+
@uid = uid
|
10
|
+
@mailbox = mailbox
|
11
|
+
@gmail = mailbox.instance_variable_get("@gmail") if mailbox
|
12
|
+
end
|
13
|
+
|
14
|
+
def labels
|
15
|
+
@gmail.conn.uid_fetch(uid, "X-GM-LABELS")[0].attr["X-GM-LABELS"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def uid
|
19
|
+
@uid ||= @gmail.conn.uid_search(['HEADER', 'Message-ID', message_id])[0]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Mark message with given flag.
|
23
|
+
def flag(name)
|
24
|
+
!!@gmail.mailbox(@mailbox.name) { @gmail.conn.uid_store(uid, "+FLAGS", [name]) }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Unmark message.
|
28
|
+
def unflag(name)
|
29
|
+
!!@gmail.mailbox(@mailbox.name) { @gmail.conn.uid_store(uid, "-FLAGS", [name]) }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Do commonly used operations on message.
|
33
|
+
def mark(flag)
|
34
|
+
case flag
|
35
|
+
when :read then read!
|
36
|
+
when :unread then unread!
|
37
|
+
when :deleted then delete!
|
38
|
+
when :spam then spam!
|
39
|
+
else
|
40
|
+
flag(flag)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Mark this message as a spam.
|
45
|
+
def spam!
|
46
|
+
move_to('[Gmail]/Spam')
|
47
|
+
end
|
48
|
+
|
49
|
+
# Mark as read.
|
50
|
+
def read!
|
51
|
+
flag(:Seen)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Mark as unread.
|
55
|
+
def unread!
|
56
|
+
unflag(:Seen)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Mark message with star.
|
60
|
+
def star!
|
61
|
+
flag('[Gmail]/Starred')
|
62
|
+
end
|
63
|
+
|
64
|
+
# Remove message from list of starred.
|
65
|
+
def unstar!
|
66
|
+
unflag('[Gmail]/Starred')
|
67
|
+
end
|
68
|
+
|
69
|
+
# Move to trash / bin.
|
70
|
+
def delete!
|
71
|
+
@mailbox.messages.delete(uid)
|
72
|
+
flag(:deleted)
|
73
|
+
|
74
|
+
# For some, it's called "Trash", for others, it's called "Bin". Support both.
|
75
|
+
trash = @gmail.labels.exist?('[Gmail]/Bin') ? '[Gmail]/Bin' : '[Gmail]/Trash'
|
76
|
+
move_to(trash) unless %w[[Gmail]/Spam [Gmail]/Bin [Gmail]/Trash].include?(@mailbox.name)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Archive this message.
|
80
|
+
def archive!
|
81
|
+
move_to('[Gmail]/All Mail')
|
82
|
+
end
|
83
|
+
|
84
|
+
# Move to given box and delete from others.
|
85
|
+
def move_to(name, from=nil)
|
86
|
+
label(name, from)
|
87
|
+
delete! if !%w[[Gmail]/Bin [Gmail]/Trash].include?(name)
|
88
|
+
end
|
89
|
+
alias :move :move_to
|
90
|
+
|
91
|
+
# Move message to given and delete from others. When given mailbox doesn't
|
92
|
+
# exist then it will be automaticaly created.
|
93
|
+
def move_to!(name, from=nil)
|
94
|
+
label!(name, from) && delete!
|
95
|
+
end
|
96
|
+
alias :move! :move_to!
|
97
|
+
|
98
|
+
# Mark this message with given label. When given label doesn't exist then
|
99
|
+
# it will raise <tt>NoLabelError</tt>.
|
100
|
+
#
|
101
|
+
# See also <tt>Gmail::Message#label!</tt>.
|
102
|
+
def label(name, from=nil)
|
103
|
+
@gmail.mailbox(Net::IMAP.encode_utf7(from || @mailbox.external_name)) { @gmail.conn.uid_copy(uid, Net::IMAP.encode_utf7(name)) }
|
104
|
+
rescue Net::IMAP::NoResponseError
|
105
|
+
raise NoLabelError, "Label '#{name}' doesn't exist!"
|
106
|
+
end
|
107
|
+
|
108
|
+
# Mark this message with given label. When given label doesn't exist then
|
109
|
+
# it will be automaticaly created.
|
110
|
+
#
|
111
|
+
# See also <tt>Gmail::Message#label</tt>.
|
112
|
+
def label!(name, from=nil)
|
113
|
+
label(name, from)
|
114
|
+
rescue NoLabelError
|
115
|
+
@gmail.labels.add(Net::IMAP.encode_utf7(name))
|
116
|
+
label(name, from)
|
117
|
+
end
|
118
|
+
alias :add_label :label!
|
119
|
+
alias :add_label! :label!
|
120
|
+
|
121
|
+
# Remove given label from this message.
|
122
|
+
def remove_label!(name)
|
123
|
+
move_to('[Gmail]/All Mail', name)
|
124
|
+
end
|
125
|
+
alias :delete_label! :remove_label!
|
126
|
+
|
127
|
+
def inspect
|
128
|
+
"#<Gmail::Message#{'0x%04x' % (object_id << 1)} mailbox=#{@mailbox.external_name}#{' uid='+@uid.to_s if @uid}#{' message_id='+@message_id.to_s if @message_id}>"
|
129
|
+
end
|
130
|
+
|
131
|
+
def method_missing(meth, *args, &block)
|
132
|
+
# Delegate rest directly to the message.
|
133
|
+
if envelope.respond_to?(meth)
|
134
|
+
envelope.send(meth, *args, &block)
|
135
|
+
elsif message.respond_to?(meth)
|
136
|
+
message.send(meth, *args, &block)
|
137
|
+
else
|
138
|
+
super(meth, *args, &block)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def respond_to?(meth, *args, &block)
|
143
|
+
if envelope.respond_to?(meth)
|
144
|
+
return true
|
145
|
+
elsif message.respond_to?(meth)
|
146
|
+
return true
|
147
|
+
else
|
148
|
+
super(meth, *args, &block)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def envelope
|
153
|
+
@envelope ||= @gmail.mailbox(@mailbox.name) {
|
154
|
+
@gmail.conn.uid_fetch(uid, "ENVELOPE")[0].attr["ENVELOPE"]
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
def message
|
159
|
+
@message ||= Mail.new(@gmail.mailbox(@mailbox.name) {
|
160
|
+
@gmail.conn.uid_fetch(uid, "RFC822")[0].attr["RFC822"] # RFC822
|
161
|
+
})
|
162
|
+
end
|
163
|
+
alias_method :raw_message, :message
|
164
|
+
|
165
|
+
end # Message
|
166
|
+
end # Gmail
|
data/lib/gmail/version.rb
CHANGED
@@ -1,12 +1,3 @@
|
|
1
|
-
module Gmail
|
2
|
-
|
3
|
-
|
4
|
-
MINOR = 4
|
5
|
-
PATCH = 0
|
6
|
-
STRING = [MAJOR, MINOR, PATCH].join('.')
|
7
|
-
end # Version
|
8
|
-
|
9
|
-
def self.version # :nodoc:
|
10
|
-
Version::STRING
|
11
|
-
end
|
12
|
-
end # Gmail
|
1
|
+
module Gmail
|
2
|
+
VERSION = "0.4.2"
|
3
|
+
end # Gmail
|
data/spec/account.yml.example
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
- "test@gmail.com"
|
1
|
+
- "test@gmail.com"
|
2
2
|
- "test"
|
data/spec/client_spec.rb
CHANGED
@@ -1,173 +1,178 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Gmail client (Plain)" do
|
4
|
-
subject { Gmail::Client::Plain }
|
5
|
-
|
6
|
-
context "on initialize" do
|
7
|
-
it "should set username, password and options" do
|
8
|
-
client = subject.new("test@gmail.com", "pass", :foo => :bar)
|
9
|
-
client.username.should == "test@gmail.com"
|
10
|
-
client.password.should == "pass"
|
11
|
-
client.options[:foo].should == :bar
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should convert simple name to gmail email" do
|
15
|
-
client = subject.new("test", "pass")
|
16
|
-
client.username.should == "test@gmail.com"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
context "instance" do
|
21
|
-
def mock_client(&block)
|
22
|
-
client = Gmail::Client::Plain.new(*TEST_ACCOUNT)
|
23
|
-
if block_given?
|
24
|
-
client.connect
|
25
|
-
yield client
|
26
|
-
client.logout
|
27
|
-
end
|
28
|
-
client
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should connect to GMail IMAP service" do
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
client
|
40
|
-
client.
|
41
|
-
client.
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
client
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
client
|
57
|
-
client.
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
client
|
64
|
-
client.
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
mail
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
mail
|
90
|
-
mail.
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
mail
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
mock_client
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
labels
|
148
|
-
|
149
|
-
|
150
|
-
it "should
|
151
|
-
labels = subject
|
152
|
-
labels.
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
labels
|
158
|
-
labels.
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
labels
|
166
|
-
labels.
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Gmail client (Plain)" do
|
4
|
+
subject { Gmail::Client::Plain }
|
5
|
+
|
6
|
+
context "on initialize" do
|
7
|
+
it "should set username, password and options" do
|
8
|
+
client = subject.new("test@gmail.com", "pass", :foo => :bar)
|
9
|
+
client.username.should == "test@gmail.com"
|
10
|
+
client.password.should == "pass"
|
11
|
+
client.options[:foo].should == :bar
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should convert simple name to gmail email" do
|
15
|
+
client = subject.new("test", "pass")
|
16
|
+
client.username.should == "test@gmail.com"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "instance" do
|
21
|
+
def mock_client(&block)
|
22
|
+
client = Gmail::Client::Plain.new(*TEST_ACCOUNT)
|
23
|
+
if block_given?
|
24
|
+
client.connect
|
25
|
+
yield client
|
26
|
+
client.logout
|
27
|
+
end
|
28
|
+
client
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should connect to GMail IMAP service" do
|
32
|
+
client = mock_client
|
33
|
+
client.connect!.should be_true
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should properly login to valid GMail account" do
|
37
|
+
client = mock_client
|
38
|
+
client.connect.should be_true
|
39
|
+
client.login.should be_true
|
40
|
+
client.should be_logged_in
|
41
|
+
client.logout
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should raise error when given GMail account is invalid and errors enabled" do
|
45
|
+
lambda {
|
46
|
+
client = Gmail::Client::Plain.new("foo", "bar")
|
47
|
+
client.connect.should be_true
|
48
|
+
client.login!.should_not be_nil
|
49
|
+
}.should raise_error
|
50
|
+
### FIX: can someone dig to the bottom of this? We are getting NoMethodError instead of Gmail::Client::AuthorizationError in 1.9
|
51
|
+
end
|
52
|
+
|
53
|
+
it "shouldn't raise error even though GMail account is invalid" do
|
54
|
+
lambda {
|
55
|
+
client = Gmail::Client::Plain.new("foo", "bar")
|
56
|
+
client.connect.should be_true
|
57
|
+
expect(client.login).to_not be_true
|
58
|
+
}.should_not raise_error
|
59
|
+
end
|
60
|
+
|
61
|
+
it "shouldn't login when given GMail account is invalid" do
|
62
|
+
client = Gmail::Client::Plain.new("foo", "bar")
|
63
|
+
client.connect.should be_true
|
64
|
+
client.login.should be_false
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should properly logout from GMail" do
|
68
|
+
client = mock_client
|
69
|
+
client.connect
|
70
|
+
client.login.should be_true
|
71
|
+
client.logout.should be_true
|
72
|
+
client.should_not be_logged_in
|
73
|
+
end
|
74
|
+
|
75
|
+
it "#connection should automatically log in to GMail account when it's called" do
|
76
|
+
mock_client do |client|
|
77
|
+
client.expects(:login).once.returns(false)
|
78
|
+
client.connection.should_not be_nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should properly compose message" do
|
83
|
+
mail = mock_client.compose do
|
84
|
+
from "test@gmail.com"
|
85
|
+
to "friend@gmail.com"
|
86
|
+
subject "Hello world!"
|
87
|
+
end
|
88
|
+
mail.from.should == ["test@gmail.com"]
|
89
|
+
mail.to.should == ["friend@gmail.com"]
|
90
|
+
mail.subject.should == "Hello world!"
|
91
|
+
end
|
92
|
+
|
93
|
+
it "#compose should automatically add `from` header when it is not specified" do
|
94
|
+
mail = mock_client.compose
|
95
|
+
mail.from.should == [TEST_ACCOUNT[0]]
|
96
|
+
mail = mock_client.compose(Mail.new)
|
97
|
+
mail.from.should == [TEST_ACCOUNT[0]]
|
98
|
+
mail = mock_client.compose {}
|
99
|
+
mail.from.should == [TEST_ACCOUNT[0]]
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should deliver inline composed email" do
|
103
|
+
mock_client do |client|
|
104
|
+
client.deliver do
|
105
|
+
to TEST_ACCOUNT[0]
|
106
|
+
subject "Hello world!"
|
107
|
+
body "Yeah, hello there!"
|
108
|
+
end.should be_true
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should not raise error when mail can't be delivered and errors are disabled" do
|
113
|
+
lambda {
|
114
|
+
client = mock_client
|
115
|
+
client.deliver(Mail.new {}).should be_false
|
116
|
+
}.should_not raise_error
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should raise error when mail can't be delivered and errors are disabled" do
|
120
|
+
lambda {
|
121
|
+
client = mock_client
|
122
|
+
client.deliver!(Mail.new {})
|
123
|
+
}.should raise_error(Gmail::Client::DeliveryError)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should properly switch to given mailbox" do
|
127
|
+
mock_client do |client|
|
128
|
+
mailbox = client.mailbox("INBOX")
|
129
|
+
mailbox.should be_kind_of(Gmail::Mailbox)
|
130
|
+
mailbox.name.should == "INBOX"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should properly switch to given mailbox using block style" do
|
135
|
+
mock_client do |client|
|
136
|
+
client.mailbox("INBOX") do |mailbox|
|
137
|
+
mailbox.should be_kind_of(Gmail::Mailbox)
|
138
|
+
mailbox.name.should == "INBOX"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context "labels" do
|
144
|
+
subject {
|
145
|
+
client = Gmail::Client::Plain.new(*TEST_ACCOUNT)
|
146
|
+
client.connect
|
147
|
+
client.labels
|
148
|
+
}
|
149
|
+
|
150
|
+
it "should get list of all available labels" do
|
151
|
+
labels = subject
|
152
|
+
labels.all.should include("INBOX")
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should be able to check if there is given label defined" do
|
156
|
+
labels = subject
|
157
|
+
labels.exists?("INBOX").should be_true
|
158
|
+
labels.exists?("FOOBAR").should be_false
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should be able to create given label" do
|
162
|
+
labels = subject
|
163
|
+
labels.create("MYLABEL")
|
164
|
+
labels.exists?("MYLABEL").should be_true
|
165
|
+
labels.create("MYLABEL").should be_false
|
166
|
+
labels.delete("MYLABEL")
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should be able to remove existing label" do
|
170
|
+
labels = subject
|
171
|
+
labels.create("MYLABEL")
|
172
|
+
labels.delete("MYLABEL").should be_true
|
173
|
+
labels.exists?("MYLABEL").should be_false
|
174
|
+
labels.delete("MYLABEL").should be_false
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|