copy-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +10 -0
  6. data/LICENSE +23 -0
  7. data/README.md +232 -0
  8. data/Rakefile +8 -0
  9. data/copy.gemspec +24 -0
  10. data/lib/copy.rb +85 -0
  11. data/lib/copy/base.rb +43 -0
  12. data/lib/copy/client.rb +70 -0
  13. data/lib/copy/file.rb +134 -0
  14. data/lib/copy/link.rb +52 -0
  15. data/lib/copy/operations/activity.rb +27 -0
  16. data/lib/copy/operations/all.rb +31 -0
  17. data/lib/copy/operations/base.rb +47 -0
  18. data/lib/copy/operations/create.rb +20 -0
  19. data/lib/copy/operations/delete.rb +25 -0
  20. data/lib/copy/operations/find.rb +21 -0
  21. data/lib/copy/operations/meta.rb +20 -0
  22. data/lib/copy/operations/show.rb +20 -0
  23. data/lib/copy/operations/update.rb +21 -0
  24. data/lib/copy/request/base.rb +41 -0
  25. data/lib/copy/request/connection.rb +120 -0
  26. data/lib/copy/request/helpers.rb +36 -0
  27. data/lib/copy/request/info.rb +41 -0
  28. data/lib/copy/request/validator.rb +53 -0
  29. data/lib/copy/revision.rb +25 -0
  30. data/lib/copy/session.rb +56 -0
  31. data/lib/copy/user.rb +24 -0
  32. data/lib/copy/version.rb +3 -0
  33. data/spec/copy/base_spec.rb +12 -0
  34. data/spec/copy/client_spec.rb +69 -0
  35. data/spec/copy/file_spec.rb +306 -0
  36. data/spec/copy/link_spec.rb +238 -0
  37. data/spec/copy/request/base_spec.rb +53 -0
  38. data/spec/copy/request/connection_spec.rb +73 -0
  39. data/spec/copy/request/info_spec.rb +27 -0
  40. data/spec/copy/request/validator_spec.rb +13 -0
  41. data/spec/copy/revision_spec.rb +42 -0
  42. data/spec/copy/user_spec.rb +119 -0
  43. data/spec/copy_spec.rb +52 -0
  44. data/spec/fixtures/hola.txt +1 -0
  45. data/spec/spec_helper.rb +12 -0
  46. metadata +170 -0
@@ -0,0 +1,3 @@
1
+ module Copy
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,12 @@
1
+ require "spec_helper"
2
+
3
+ describe Copy::Base do
4
+ describe "#parse_timestamps" do
5
+ context "given #created_time is present" do
6
+ it "creates a Time object" do
7
+ base = Copy::Base.new(created_time: 1358300444)
8
+ expect(base.created_time.class).to eql(Time)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,69 @@
1
+ require "spec_helper"
2
+
3
+ describe Copy::Client do
4
+ let(:consumer_key) { '_your_consumen_key_' }
5
+ let(:consumer_secret) { '_your_consumen_secret_' }
6
+ let(:access_token) do
7
+ {
8
+ token: '_your_user_token_',
9
+ secret: '_your_secret_token_'
10
+ }
11
+ end
12
+ let(:client) { Copy::Client.new(session) }
13
+ let(:session) { Copy::Session.new(access_token) }
14
+ let(:valid_attributes) { JSON.parse('{}') }
15
+
16
+ before :each do
17
+ allow(Copy).to receive(:request).and_return(valid_attributes)
18
+ end
19
+
20
+ describe '#initialize' do
21
+ it 'initializes attributes correctly' do
22
+ expect(client.session).to eql(session)
23
+ end
24
+ it 'raises Copy::AuthenticationError if session is invalid' do
25
+ allow(session).to receive(:valid?).and_return(false)
26
+
27
+ expect{client}.to raise_error{ Copy::AuthenticationError }
28
+ end
29
+ end
30
+
31
+ describe '#perform!' do
32
+ it 'is private' do
33
+ expect{client.perform!(:user, :show)}.to raise_error
34
+ end
35
+ it 'raises Copy::AuthenticationError if session is invalid' do
36
+ allow(client).to receive(:session).and_return(nil)
37
+ expect{client.perform!(:user, :show)}.to raise_error{ Copy::AuthenticationError }
38
+ end
39
+ it 'calls to the given resource' do
40
+ allow(Copy::User).to receive(:show).and_return(Copy::User.new)
41
+ expect(Copy::User).to receive(:show).with({ session: session })
42
+
43
+ client.send(:perform!, :user, :show)
44
+ end
45
+ end
46
+
47
+ describe '#options_with_session' do
48
+ it 'is private' do
49
+ expect{client.options_with_session({})}.to raise_error
50
+ end
51
+ it 'adds the session to the given options' do
52
+ expect(client.send(:options_with_session,{})).to include(:session)
53
+ expect(client.send(:options_with_session,{})[:session]).to eql(session)
54
+ end
55
+ end
56
+
57
+ describe '#resource' do
58
+ it 'is private' do
59
+ expect{client.resource('user')}.to raise_error
60
+ end
61
+ it 'gives the correct api resource class' do
62
+ expect(client.send(:resource, 'user')).to eql(Copy::User)
63
+ end
64
+ it 'gives nil if there is no resource for the given name' do
65
+ expect(client.send(:resource, 'icecream')).to be_nil
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,306 @@
1
+ require "spec_helper"
2
+
3
+ describe Copy::File do
4
+ let(:consumer_key) { '_your_consumen_key_' }
5
+ let(:consumer_secret) { '_your_consumen_secret_' }
6
+ let(:access_token) do
7
+ {
8
+ token: '_your_user_token_',
9
+ secret: '_your_secret_token_'
10
+ }
11
+ end
12
+ let(:client) { Copy::Client.new(session) }
13
+ let(:session) { Copy::Session.new(access_token) }
14
+ let(:valid_attributes) do
15
+ JSON.parse %{
16
+ {
17
+ "id": "/copy",
18
+ "path": "/",
19
+ "name": "Copy Folder",
20
+ "type": "copy",
21
+ "size": null,
22
+ "date_last_synced": null,
23
+ "stub": false,
24
+ "children": [
25
+ {
26
+ "id": "/copy/Applications",
27
+ "path": "/Applications",
28
+ "name": "Applications",
29
+ "link_name": "",
30
+ "token": "",
31
+ "permissions": "",
32
+ "public": false,
33
+ "type": "dir",
34
+ "size": null,
35
+ "date_last_synced": 1360079517,
36
+ "stub": true,
37
+ "counts": [
38
+ ],
39
+ "recipient_confirmed": false,
40
+ "object_available": true,
41
+ "links": [
42
+ {
43
+ "id": "hPTBeqqN9Bg9",
44
+ "public": true,
45
+ "expires": false,
46
+ "expired": false,
47
+ "url": "https://copy.com/hPTBeqqN9Bg9/Applications",
48
+ "url_short": "https://copy.com/hPTBeqqN9Bg9",
49
+ "recipients": [
50
+ ],
51
+ "creator_id": "1381231",
52
+ "confirmation_required": false
53
+ }
54
+ ],
55
+ "url": "https://copy.com/web/Applications",
56
+ "thumb": false
57
+ },
58
+ {
59
+ "id": "/copy/binding-of-isaac.png",
60
+ "path": "/binding-of-isaac.png",
61
+ "name": "binding-of-isaac.png",
62
+ "link_name": "",
63
+ "token": "",
64
+ "permissions": "",
65
+ "public": false,
66
+ "type": "file",
67
+ "size": 164850,
68
+ "date_last_synced": 1363573463,
69
+ "stub": true,
70
+ "counts": [
71
+ ],
72
+ "recipient_confirmed": false,
73
+ "object_available": true,
74
+ "links": [
75
+ ],
76
+ "url": "https://copy.com/web/bad-binding-of-isaac.png",
77
+ "revision_id": 2897,
78
+ "thumb": "https://copy.com/thumbs/bad-binding-of-isaac.png",
79
+ "thumb_original_dimensions": {
80
+ "width": 800,
81
+ "height": 620
82
+ }
83
+ }
84
+ ]
85
+ }
86
+ }
87
+ end
88
+ let(:valid_activity_attributes) do
89
+ JSON.parse %{
90
+ {
91
+ "id": "/copy/Big%20API%20Changes/API-Changes.md/@activity",
92
+ "path": "/Big API Changes/API-Changes.md",
93
+ "name": "Activity",
94
+ "token": null,
95
+ "permissions": null,
96
+ "syncing": false,
97
+ "public": false,
98
+ "type": "file",
99
+ "size": 12670,
100
+ "date_last_synced": 1365543105,
101
+ "stub": false,
102
+ "recipient_confirmed": false,
103
+ "url": "https://copy.com/web/Big%20API%20Changes/API-Changes.md",
104
+ "revision_id": "5000",
105
+ "thumb": null,
106
+ "share": null,
107
+ "counts": [
108
+ ],
109
+ "links": [
110
+ ],
111
+ "revisions": [
112
+ {
113
+ "revision_id": "5000",
114
+ "modified_time": 1365543105,
115
+ "size": 12670,
116
+ "latest": true,
117
+ "conflict": false,
118
+ "id": "/copy/Big%20API%20Changes/API-Changes.md/@activity/@time:1365543105",
119
+ "type": "revision",
120
+ "creator": {
121
+ "user_id": "1381231",
122
+ "created_time": 1358175510,
123
+ "email": "thomashunter@example.com",
124
+ "first_name": "Thomas",
125
+ "last_name": "Hunter",
126
+ "confirmed": true
127
+ }
128
+ },
129
+ {
130
+ "revision_id": "4900",
131
+ "modified_time": 1365542000,
132
+ "size": 12661,
133
+ "latest": false,
134
+ "conflict": true,
135
+ "id": "/copy/Big%20API%20Changes/API-Changes.md/@activity/@time:1365542000",
136
+ "type": "revision",
137
+ "creator": {
138
+ "user_id": "1381231",
139
+ "created_time": 1358175510,
140
+ "email": "thomashunter@example.com",
141
+ "first_name": "Thomas",
142
+ "last_name": "Hunter",
143
+ "confirmed": true
144
+ }
145
+ },
146
+ {
147
+ "revision_id": "4800",
148
+ "modified_time": 1365543073,
149
+ "size": 12658,
150
+ "latest": false,
151
+ "conflict": false,
152
+ "id": "/copy/Big%20API%20Changes/API-Changes.md/@activity/@time:1365543073",
153
+ "type": "revision",
154
+ "creator": {
155
+ "user_id": "1381231",
156
+ "created_time": 1358175510,
157
+ "email": "thomashunter@example.com",
158
+ "first_name": "Thomas",
159
+ "last_name": "Hunter",
160
+ "confirmed": true
161
+ }
162
+ }
163
+ ]
164
+ }
165
+ }
166
+ end
167
+ let (:file) do
168
+ Copy::File.new(valid_attributes)
169
+ end
170
+
171
+ before :each do
172
+ Copy.config do |configuration|
173
+ configuration[:consumer_key] = consumer_key
174
+ configuration[:consumer_secret] = consumer_secret
175
+ end
176
+ end
177
+
178
+ describe "#initialize" do
179
+ it 'initializes all attributes correctly' do
180
+ expect(file.path).to eql('/')
181
+ expect(file.id).to eql('/copy')
182
+ expect(file.name).to eql('Copy Folder')
183
+ expect(file.type).to eql('copy')
184
+ expect(file.children.map {|a| a.name }).to eql(%w{Applications binding-of-isaac.png})
185
+ end
186
+ end
187
+
188
+ describe ".show" do
189
+ let(:file_show) { Copy::File.show( id: '/', session: session ) }
190
+ before :each do
191
+ allow(Copy).to receive(:request).and_return(valid_attributes)
192
+ end
193
+ it "makes a new GET request using the correct API endpoint to receive a specific user" do
194
+ expect(Copy).to receive(:request).with(:get, nil, "meta/", {}, { session: session })
195
+ file_show
196
+ end
197
+ it 'returns a file with the correct path' do
198
+ expect(file_show.path).to eql('/')
199
+ end
200
+ it 'returns a file with the correct id' do
201
+ expect(file_show.id).to eql('/copy')
202
+ end
203
+ it 'returns a file with the correct name' do
204
+ expect(file_show.name).to eql('Copy Folder')
205
+ end
206
+ it 'returns a file with the correct type' do
207
+ expect(file_show.type).to eql('copy')
208
+ end
209
+ end
210
+
211
+ describe ".activity" do
212
+ let(:file_activity) { Copy::File.activity( id: '/copy/readme.txt', session: session ) }
213
+ before :each do
214
+ allow(Copy).to receive(:request).and_return(valid_activity_attributes)
215
+ end
216
+ it "makes a new GET request using the correct API endpoint to receive a specific user" do
217
+ expect(Copy).to receive(:request).with(:get, nil, "meta/copy/readme.txt/@activity", {}, { session: session })
218
+ file_activity
219
+ end
220
+ it 'returns a file with the correct revision_id' do
221
+ expect(file_activity.revision_id).to eql('5000')
222
+ end
223
+ it 'returns a file with the correct revisons data' do
224
+ expect(file_activity.revisions.first.class).to eql(Copy::Revision)
225
+ end
226
+ end
227
+
228
+ describe ".delete" do
229
+ let(:file_delete) { Copy::File.delete( id: '/copy/readme.txt', session: session ) }
230
+ before :each do
231
+ allow(Copy).to receive(:request).and_return(true)
232
+ end
233
+ it "makes a new GET request using the correct API endpoint to receive a specific user" do
234
+ expect(Copy).to receive(:request).with(:delete, nil, "files/copy/readme.txt", {}, { session: session })
235
+ file_delete
236
+ end
237
+ it 'returns true' do
238
+ expect(file_delete).to be_true
239
+ end
240
+ end
241
+
242
+ describe ".create" do
243
+ let(:file) do
244
+ path = File.expand_path(File.join(File.dirname(__FILE__), "../fixtures/hola.txt"))
245
+ File.open(path)
246
+ end
247
+ let(:file_create) { Copy::File.create( path: 'path', session: session, file: file ) }
248
+ before :each do
249
+ allow(Copy).to receive(:request).and_return(valid_attributes)
250
+ end
251
+ it "makes a new GET request using the correct API endpoint to receive a specific file" do
252
+ expect(Copy).to receive(:request).with(
253
+ :post,
254
+ nil,
255
+ "files/path",
256
+ {
257
+ :file_attrs => {
258
+ :name=> ::File.basename(file.path),
259
+ :local_path=> file.path
260
+ },
261
+ :file => file
262
+ },
263
+ { session: session }
264
+ )
265
+ file_create
266
+ end
267
+ it 'returns true' do
268
+ expect(file_create.class).to be(Copy::File)
269
+ end
270
+ end
271
+
272
+ describe ".delete" do
273
+ let(:file_delete) { Copy::File.delete( id: '/path/to/file.txt', session: session) }
274
+ before :each do
275
+ allow(Copy).to receive(:request).and_return({})
276
+ end
277
+ it "makes a new GET request using the correct API endpoint to delete a specific file" do
278
+ expect(Copy).to receive(:request).with(:delete, nil, "files/path/to/file.txt", {}, { session: session })
279
+ file_delete
280
+ end
281
+ it 'returns true' do
282
+ expect(file_delete).to be_true
283
+ end
284
+ end
285
+
286
+ describe "#is_dir?" do
287
+ it 'rerurns false if file is a file' do
288
+ allow(file).to receive(:type).and_return('file')
289
+
290
+ expect(file.is_dir?).to be_false
291
+ end
292
+ it 'returns true othercase' do
293
+ allow(file).to receive(:type).and_return('root')
294
+
295
+ expect(file.is_dir?).to be_true
296
+ end
297
+ end
298
+
299
+ describe "#stubbed?" do
300
+ it 'returns stub field value' do
301
+ allow(file).to receive(:stub).and_return(false)
302
+
303
+ expect(file.stubbed?).to be_false
304
+ end
305
+ end
306
+ end
@@ -0,0 +1,238 @@
1
+ require "spec_helper"
2
+
3
+ describe Copy::Link do
4
+ let(:consumer_key) { '_your_consumen_key_' }
5
+ let(:consumer_secret) { '_your_consumen_secret_' }
6
+ let(:access_token) do
7
+ {
8
+ token: '_your_user_token_',
9
+ secret: '_your_secret_token_'
10
+ }
11
+ end
12
+ let(:client) { Copy::Client.new(session) }
13
+ let(:session) { Copy::Session.new(access_token) }
14
+ let(:valid_attributes) do
15
+ JSON.parse %{
16
+ {
17
+ "id": "wFIK8aMIDvh2",
18
+ "name": "Such a cool Link",
19
+ "public": false,
20
+ "url": "https://copy.com/wFIK8aMIDvh2",
21
+ "url_short": "https://copy.com/wFIK8aMIDvh2",
22
+ "creator_id": "110660",
23
+ "created_time": 1366825349,
24
+ "object_count": 1,
25
+ "confirmation_required": false,
26
+ "status": "viewed",
27
+ "permissions": "sync",
28
+ "recipients": [
29
+ {
30
+ "contact_type": "user",
31
+ "contact_id": "user-1381231",
32
+ "contact_source": "link-3514165",
33
+ "user_id": "1381231",
34
+ "email": "thomashunter@example.com",
35
+ "first_name": "Thomas",
36
+ "last_name": "Hunter",
37
+ "permissions": "sync",
38
+ "emails": [
39
+ {
40
+ "primary": true,
41
+ "confirmed": true,
42
+ "email": "thomashunter@example.com",
43
+ "gravatar": "eca957c6552e783627a0ced1035e1888"
44
+ },
45
+ {
46
+ "primary": false,
47
+ "confirmed": true,
48
+ "email": "thomashunter@example.net",
49
+ "gravatar": "c0e344ddcbabb383f94b1bd3486e55ba"
50
+ }
51
+ ]
52
+ }
53
+ ]
54
+ }
55
+ }
56
+ end
57
+ let (:link) do
58
+ Copy::Link.new(valid_attributes)
59
+ end
60
+
61
+ before :each do
62
+ Copy.config do |configuration|
63
+ configuration[:consumer_key] = consumer_key
64
+ configuration[:consumer_secret] = consumer_secret
65
+ end
66
+ end
67
+
68
+ describe "#initialize" do
69
+ it 'initializes all attributes correctly' do
70
+ expect(link.url).to eql('https://copy.com/wFIK8aMIDvh2')
71
+ expect(link.id).to eql('wFIK8aMIDvh2')
72
+ expect(link.name).to eql('Such a cool Link')
73
+ expect(link.public).to be_false
74
+ expect(link.recipients.map {|a| a.id }).to eql(%w{1381231})
75
+ end
76
+ end
77
+
78
+ describe ".all" do
79
+ let(:link_all) { Copy::Link.all( session: session ) }
80
+ before :each do
81
+ allow(Copy).to receive(:request).and_return([valid_attributes])
82
+ end
83
+ it "makes a new GET request using the correct API endpoint to receive links" do
84
+ expect(Copy).to receive(:request).with(:get, nil, "links", {}, { session: session })
85
+ link_all
86
+ end
87
+ it 'returns a array of links' do
88
+ expect(link_all.first.class).to eql(Copy::Link)
89
+ end
90
+ it 'returns the correct links' do
91
+ expect(link_all.first.id).to eql('wFIK8aMIDvh2')
92
+ end
93
+ end
94
+
95
+ describe ".show" do
96
+ let(:link_show) { Copy::Link.show( id: 'wFIK8aMIDvh2', session: session ) }
97
+ before :each do
98
+ allow(Copy).to receive(:request).and_return(valid_attributes)
99
+ end
100
+ it "makes a new GET request using the correct API endpoint to receive a specific link" do
101
+ expect(Copy).to receive(:request).with(:get, nil, "links/wFIK8aMIDvh2", {}, { session: session })
102
+ link_show
103
+ end
104
+ it 'returns a link with the correct id' do
105
+ expect(link_show.id).to eql('wFIK8aMIDvh2')
106
+ end
107
+ end
108
+
109
+ describe ".create" do
110
+ let(:create_attributes) do
111
+ {
112
+ public: true,
113
+ name: "My Cool Shared Files",
114
+ paths: [
115
+ "/path/to/file.txt"
116
+ ]
117
+ }
118
+ end
119
+ let(:valid_create_response) do
120
+ JSON.parse(%{
121
+ {
122
+ "id": "MBrss3roGDk4",
123
+ "name": "My Cool Shared Files",
124
+ "public": true,
125
+ "url": "https://copy.com/MBrss3roGDk4",
126
+ "url_short": "https://copy.com/MBrss3roGDk4",
127
+ "creator_id": "1381231",
128
+ "confirmation_required": false,
129
+ "status": "viewed",
130
+ "permissions": "read",
131
+ "recipients": [
132
+ ]
133
+ }
134
+ })
135
+ end
136
+ let(:link_create) { Copy::Link.create(create_attributes.merge(session: session)) }
137
+ before :each do
138
+ allow(Copy).to receive(:request).and_return(valid_create_response)
139
+ end
140
+ it "makes a new GET request using the correct API endpoint to receive a specific link" do
141
+ expect(Copy).to receive(:request).with(:post, nil, "links", create_attributes, { session: session })
142
+ link_create
143
+ end
144
+ it 'returns a link with the correct name' do
145
+ expect(link_create.name).to eql('My Cool Shared Files')
146
+ end
147
+ it 'returns a link with the correct public' do
148
+ expect(link_create.public).to eql(true)
149
+ end
150
+ end
151
+
152
+ describe ".delete" do
153
+ let(:link_delete) { Copy::Link.delete(id: 'wFIK8aMIDvh2', session: session) }
154
+ before :each do
155
+ allow(Copy).to receive(:request).and_return({})
156
+ end
157
+ it "makes a new GET request using the correct API endpoint to receive a specific link" do
158
+ expect(Copy).to receive(:request).with(:delete, nil, "links/wFIK8aMIDvh2", {}, { session: session })
159
+ link_delete
160
+ end
161
+ end
162
+
163
+
164
+ describe ".meta" do
165
+ let(:valid_attributes_meta) do
166
+ JSON.parse(%{
167
+ {
168
+ "id": "/links/e6aauE2WodKj",
169
+ "path": "/e6aauE2WodKj",
170
+ "name": "Artwork",
171
+ "token": "e6aauE2WodKj",
172
+ "creator_id": "1381231",
173
+ "permissions": "read",
174
+ "syncing": false,
175
+ "public": true,
176
+ "type": "link",
177
+ "size": null,
178
+ "date_last_synced": null,
179
+ "stub": false,
180
+ "recipient_confirmed": false,
181
+ "counts": [
182
+ ],
183
+ "children_count": null,
184
+ "mime_type": "",
185
+ "url": "http://copy.local/e6aauE2WodKj",
186
+ "links": [
187
+ ],
188
+ "thumb": null,
189
+ "share": null,
190
+ "children": [
191
+ {
192
+ "id": "/links/e6aauE2WodKj/Artwork",
193
+ "path": "/e6aauE2WodKj/Artwork",
194
+ "name": "Artwork",
195
+ "link_name": null,
196
+ "token": null,
197
+ "creator_id": null,
198
+ "permissions": null,
199
+ "public": false,
200
+ "type": "dir",
201
+ "size": null,
202
+ "date_last_synced": null,
203
+ "stub": true,
204
+ "recipient_confirmed": false,
205
+ "object_available": true,
206
+ "counts": [
207
+ ],
208
+ "mime_type": "",
209
+ "list_index": 0,
210
+ "url": "http://copy.local/e6aauE2WodKj/Artwork",
211
+ "revision": 0,
212
+ "thumb": null,
213
+ "links": [
214
+ ]
215
+ }
216
+ ]
217
+ }
218
+ })
219
+ end
220
+ let(:link_meta) { Copy::Link.meta(id: 'wFIK8aMIDvh2', session: session) }
221
+ before :each do
222
+ allow(Copy).to receive(:request).and_return(valid_attributes_meta)
223
+ end
224
+ it "makes a new GET request using the correct API endpoint to receive a specific link" do
225
+ expect(Copy).to receive(:request).with(:get, nil, "meta/links/wFIK8aMIDvh2", {}, { session: session })
226
+ link_meta
227
+ end
228
+
229
+ it "returns a link object" do
230
+ expect(link_meta.class).to eql(Copy::Link)
231
+ end
232
+
233
+ it "parses children as files" do
234
+ expect(link_meta.children.first.class).to eql(Copy::File)
235
+ end
236
+ end
237
+
238
+ end