uploadcare-ruby 2.1.2 → 3.0.3

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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/gem-push.yml +20 -0
  3. data/.github/workflows/ruby.yml +52 -0
  4. data/.gitignore +13 -6
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +20 -0
  7. data/.yardopts +4 -0
  8. data/CHANGELOG.md +24 -51
  9. data/DEVELOPMENT.md +18 -0
  10. data/Gemfile +2 -0
  11. data/LICENSE +1 -1
  12. data/README.md +164 -578
  13. data/Rakefile +5 -5
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/lib/uploadcare.rb +36 -32
  17. data/lib/uploadcare/api/api.rb +25 -0
  18. data/lib/uploadcare/client/file_client.rb +44 -0
  19. data/lib/uploadcare/client/file_list_client.rb +46 -0
  20. data/lib/uploadcare/client/group_client.rb +45 -0
  21. data/lib/uploadcare/client/multipart_upload/chunks_client.rb +46 -0
  22. data/lib/uploadcare/client/multipart_upload_client.rb +62 -0
  23. data/lib/uploadcare/client/project_client.rb +18 -0
  24. data/lib/uploadcare/client/rest_client.rb +73 -0
  25. data/lib/uploadcare/client/rest_group_client.rb +23 -0
  26. data/lib/uploadcare/client/upload_client.rb +35 -0
  27. data/lib/uploadcare/client/uploader_client.rb +93 -0
  28. data/lib/uploadcare/client/webhook_client.rb +43 -0
  29. data/lib/uploadcare/concern/error_handler.rb +54 -0
  30. data/lib/uploadcare/concern/throttle_handler.rb +25 -0
  31. data/lib/uploadcare/concern/upload_error_handler.rb +32 -0
  32. data/lib/uploadcare/entity/decorator/paginator.rb +81 -0
  33. data/lib/uploadcare/entity/entity.rb +18 -0
  34. data/lib/uploadcare/entity/file.rb +81 -0
  35. data/lib/uploadcare/entity/file_list.rb +30 -0
  36. data/lib/uploadcare/entity/group.rb +41 -0
  37. data/lib/uploadcare/entity/group_list.rb +24 -0
  38. data/lib/uploadcare/entity/project.rb +13 -0
  39. data/lib/uploadcare/entity/uploader.rb +73 -0
  40. data/lib/uploadcare/entity/webhook.rb +14 -0
  41. data/lib/uploadcare/exception/request_error.rb +9 -0
  42. data/lib/uploadcare/exception/throttle_error.rb +14 -0
  43. data/lib/uploadcare/param/authentication_header.rb +25 -0
  44. data/lib/uploadcare/param/param.rb +10 -0
  45. data/lib/uploadcare/param/secure_auth_header.rb +37 -0
  46. data/lib/uploadcare/param/simple_auth_header.rb +14 -0
  47. data/lib/uploadcare/param/upload/signature_generator.rb +24 -0
  48. data/lib/uploadcare/param/upload/upload_params_generator.rb +23 -0
  49. data/lib/uploadcare/param/user_agent.rb +21 -0
  50. data/lib/uploadcare/ruby/version.rb +5 -0
  51. data/uploadcare-ruby.gemspec +50 -37
  52. metadata +98 -113
  53. data/.travis.yml +0 -26
  54. data/UPGRADE_NOTES.md +0 -36
  55. data/lib/uploadcare/api.rb +0 -26
  56. data/lib/uploadcare/api/file_api.rb +0 -7
  57. data/lib/uploadcare/api/file_list_api.rb +0 -19
  58. data/lib/uploadcare/api/file_storage_api.rb +0 -34
  59. data/lib/uploadcare/api/group_api.rb +0 -38
  60. data/lib/uploadcare/api/group_list_api.rb +0 -17
  61. data/lib/uploadcare/api/project_api.rb +0 -9
  62. data/lib/uploadcare/api/raw_api.rb +0 -38
  63. data/lib/uploadcare/api/uploading_api.rb +0 -71
  64. data/lib/uploadcare/api/uploading_api/upload_params.rb +0 -72
  65. data/lib/uploadcare/api/validators/file_list_options_validator.rb +0 -73
  66. data/lib/uploadcare/api/validators/group_list_options_validator.rb +0 -49
  67. data/lib/uploadcare/errors/errors.rb +0 -64
  68. data/lib/uploadcare/resources/file.rb +0 -164
  69. data/lib/uploadcare/resources/file_list.rb +0 -14
  70. data/lib/uploadcare/resources/group.rb +0 -115
  71. data/lib/uploadcare/resources/group_list.rb +0 -14
  72. data/lib/uploadcare/resources/project.rb +0 -13
  73. data/lib/uploadcare/resources/resource_list.rb +0 -83
  74. data/lib/uploadcare/rest/auth/auth.rb +0 -31
  75. data/lib/uploadcare/rest/auth/secure.rb +0 -43
  76. data/lib/uploadcare/rest/auth/simple.rb +0 -16
  77. data/lib/uploadcare/rest/connections/api_connection.rb +0 -53
  78. data/lib/uploadcare/rest/connections/upload_connection.rb +0 -22
  79. data/lib/uploadcare/rest/middlewares/auth_middleware.rb +0 -24
  80. data/lib/uploadcare/rest/middlewares/parse_json_middleware.rb +0 -33
  81. data/lib/uploadcare/rest/middlewares/raise_error_middleware.rb +0 -21
  82. data/lib/uploadcare/utils/parser.rb +0 -71
  83. data/lib/uploadcare/utils/user_agent.rb +0 -44
  84. data/lib/uploadcare/version.rb +0 -3
  85. data/spec/api/file_list_api_spec.rb +0 -95
  86. data/spec/api/file_storage_api_spec.rb +0 -88
  87. data/spec/api/group_list_api_spec.rb +0 -59
  88. data/spec/api/raw_api_spec.rb +0 -25
  89. data/spec/api/uploading_api/upload_params_spec.rb +0 -99
  90. data/spec/api/uploading_api_spec.rb +0 -59
  91. data/spec/resources/file_list_spec.rb +0 -25
  92. data/spec/resources/file_spec.rb +0 -223
  93. data/spec/resources/group_list_spec.rb +0 -25
  94. data/spec/resources/group_spec.rb +0 -101
  95. data/spec/resources/operations_spec.rb +0 -59
  96. data/spec/resources/project_spec.rb +0 -21
  97. data/spec/rest/api_connection_spec.rb +0 -68
  98. data/spec/rest/auth/secure_spec.rb +0 -66
  99. data/spec/rest/auth/simple_spec.rb +0 -31
  100. data/spec/rest/errors_spec.rb +0 -75
  101. data/spec/rest/upload_connection_spec.rb +0 -19
  102. data/spec/shared/resource_list.rb +0 -188
  103. data/spec/spec_helper.rb +0 -54
  104. data/spec/uploadcare_spec.rb +0 -43
  105. data/spec/utils/parser_spec.rb +0 -85
  106. data/spec/utils/user_agent_spec.rb +0 -46
  107. data/spec/view.png +0 -0
  108. data/spec/view2.jpg +0 -0
@@ -1,59 +0,0 @@
1
- require 'spec_helper'
2
- require 'uri'
3
- require 'socket'
4
-
5
- describe Uploadcare::Api::File do
6
- before :all do
7
- @api = API
8
- @file = @api.upload IMAGE_URL
9
- end
10
-
11
- it "freshly uploaded file should have empty operations list" do
12
- @file.should respond_to :operations
13
- @file.operations.should be_kind_of(Array)
14
- @file.operations.should be_empty
15
- end
16
-
17
- it "file created from uuid should be not loaded and without operations" do
18
- file = @api.file @file.uuid
19
- file.is_loaded?.should be false
20
- file.operations.should be_empty
21
- end
22
-
23
- it "file created from url without operations should be not be loaded and have no operations" do
24
- file = @api.file @file.cdn_url
25
- file.is_loaded?.should be false
26
- file.operations.should be_empty
27
- end
28
-
29
- it "file created from url with operations should be not be loaded and have operations" do
30
- file = @api.file @file.cdn_url + "-/crop/150x150/center/-/format/png/"
31
- file.is_loaded?.should be false
32
- file.operations.should_not be_empty
33
- end
34
-
35
- it "file should have methods for construct cdn urls with or without cdn operations" do
36
- @file.should respond_to(:cdn_url_with_operations)
37
- @file.should respond_to(:cdn_url_without_operations)
38
- end
39
-
40
- it "file should construct cdn_url with and without opreations" do
41
- url_without_operations = @file.cdn_url
42
- url_with_operations = @file.cdn_url + "-/crop/150x150/center/-/format/png/"
43
-
44
- file = @api.file url_with_operations
45
-
46
- file.cdn_url.should == (url_without_operations)
47
- file.cdn_url(true).should == (url_with_operations)
48
- end
49
-
50
- it 'should works also with exact methods' do
51
- url_without_operations = @file.cdn_url.to_s
52
- url_with_operations = @file.cdn_url + "-/crop/150x150/center/-/format/png/"
53
-
54
- file = @api.file url_with_operations
55
-
56
- file.cdn_url_with_operations.should == (url_with_operations)
57
- file.cdn_url_without_operations.should == (url_without_operations)
58
- end
59
- end
@@ -1,21 +0,0 @@
1
- require 'spec_helper'
2
- require 'uri'
3
- require 'socket'
4
-
5
- describe Uploadcare::Api::Project do
6
- before :all do
7
- @api = API
8
- @project = @api.project
9
- end
10
-
11
- it "should instantiated project" do
12
- @project.should be_kind_of Uploadcare::Api::Project
13
- end
14
-
15
- it "should respond to project api methods" do
16
- @project.should respond_to :collaborators
17
- @project.should respond_to :name
18
- @project.should respond_to :pub_key
19
- @project.should respond_to :autostore_enabled
20
- end
21
- end
@@ -1,68 +0,0 @@
1
- require 'spec_helper'
2
- require 'uri'
3
- require 'socket'
4
-
5
- describe Uploadcare::Connections::ApiConnection do
6
- let(:settings){ Uploadcare.default_settings }
7
-
8
- it 'is initializable with default settings' do
9
- expect {described_class.new(settings)}.to_not raise_error
10
- end
11
-
12
-
13
- describe 'default request headers' do
14
- subject{ described_class.new(settings).headers }
15
-
16
- it 'includes correct Accept header' do
17
- expected = "application/vnd.uploadcare-v#{settings[:api_version]}+json"
18
- expect(subject['Accept']).to eq expected
19
- end
20
-
21
- it 'includes correct User-Agent header' do
22
- expected = Uploadcare::UserAgent.new.call(settings)
23
- expect(subject['User-Agent']).to eq expected
24
- end
25
- end
26
-
27
-
28
- describe 'middleware' do
29
- subject{ described_class.new(settings).builder.handlers }
30
-
31
- it 'uses Request::Auth middleware' do
32
- expect(subject).to include(Uploadcare::Connections::Request::Auth)
33
- end
34
-
35
- it 'uses Response::ParseJson middleware' do
36
- expect(subject).to include(Uploadcare::Connections::Response::ParseJson)
37
- end
38
-
39
- it 'uses Response::RaiseError middleware' do
40
- expect(subject).to include(Uploadcare::Connections::Response::RaiseError)
41
- end
42
- end
43
-
44
-
45
- describe 'auth scheme' do
46
- it 'uses simple auth when auth_scheme: :simple setting is provided' do
47
- expect(Uploadcare::Connections::Auth::Simple).to receive(:new)
48
- described_class.new(settings.merge(auth_scheme: :simple))
49
- end
50
-
51
- it 'uses secure auth when auth_scheme: :secure setting is provided' do
52
- expect(Uploadcare::Connections::Auth::Secure).to receive(:new)
53
- described_class.new(settings.merge(auth_scheme: :secure))
54
- end
55
-
56
- it 'raises KeyError when :auth_scheme options is not provided' do
57
- expect{
58
- described_class.new(settings.reject{|k,_| k == :auth_scheme})
59
- }.to raise_error(KeyError)
60
- end
61
-
62
- it 'raises ArgumentError when provided :auth_scheme is unknown' do
63
- expect{
64
- described_class.new(settings.merge(auth_scheme: :unknown))
65
- }.to raise_error(ArgumentError)
66
- end
67
- end
68
- end
@@ -1,66 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Uploadcare::Connections::Auth::Secure do
4
- describe '#apply' do
5
- let(:env){ Faraday::Env.new(:get, nil, URI::HTTP.build(host: 'example.com'), nil, {}) }
6
- subject{ env.request_headers }
7
-
8
- before(:each) do
9
- described_class.new(public_key: 'pub', private_key: 'priv').apply(env)
10
- end
11
-
12
- it "adds Authorization header to env's request_headers" do
13
- expect(subject).to include('Authorization')
14
- end
15
-
16
- it "adds Date header to env's request_headers" do
17
- expect(subject).to include('Date')
18
- end
19
-
20
- it "uses secure authorization" do
21
- expect(subject['Authorization']).to match /Uploadcare pub:.+/
22
- end
23
- end
24
-
25
- describe 'signature' do
26
- let(:uri){ URI::HTTP.build(host: 'example.com', path: '/path', query: 'test=1') }
27
- let(:headers){ {'Content-Type' => 'application/x-www-form-urlencoded'} }
28
- let(:env){ Faraday::Env.new(:post, 'url=encoded&test=body', uri, nil, headers) }
29
-
30
- subject{ env.request_headers }
31
-
32
- before(:each) do
33
- allow(Time).to receive(:now).and_return(Time.parse('2017.02.02 12:58:50 +0000'))
34
- described_class.new(public_key: 'pub', private_key: 'priv').apply(env)
35
- end
36
-
37
- it "counts signature correctly" do
38
- expected = '71b61ed67d16f48d2e46a4ee72ca12025aeb8d1f'
39
- expect(subject['Authorization']).to eq "Uploadcare pub:#{expected}"
40
- end
41
- end
42
-
43
-
44
- describe 'integration' do
45
- let(:api){ Uploadcare::Api.new(auth_scheme: :secure) }
46
- let(:file){ api.upload IMAGE_URL }
47
-
48
- before(:each) do
49
- # ensure that secure auth is being used
50
- expect_any_instance_of(described_class).to receive(:apply).at_least(4).times.and_call_original
51
- end
52
-
53
- it 'auth works with real requests' do
54
- # request with url params
55
- expect{ api.get('/files/', limit: 1) }.not_to raise_error
56
- # request with an url-encoded body
57
- expect{
58
- retry_if(Uploadcare::Error::RequestError::BadRequest) do
59
- api.post('/files/', source: file.uuid)
60
- end
61
- }.not_to raise_error
62
- # request with an empty body and a redirect
63
- expect{ api.delete("/files/#{file.uuid}/storage/") }.not_to raise_error
64
- end
65
- end
66
- end
@@ -1,31 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Uploadcare::Connections::Auth::Simple do
4
- let(:env){ Faraday::Env.new(nil, nil, nil, nil, {}) }
5
- subject{ described_class.new(public_key: 'pub', private_key: 'priv') }
6
-
7
- describe 'apply' do
8
- it "adds Authorization header to env's request_headers" do
9
- subject.apply(env)
10
- expect(env.request_headers).to include('Authorization')
11
- end
12
-
13
- it "sets Authorization header's value correctly" do
14
- subject.apply(env)
15
- expect(env.request_headers['Authorization']).to eq "Uploadcare.Simple pub:priv"
16
- end
17
- end
18
-
19
- describe 'integration' do
20
- let(:api){ Uploadcare::Api.new(auth_scheme: :simple) }
21
-
22
- before(:each) do
23
- # ensure that simple auth is being used
24
- expect_any_instance_of(described_class).to receive(:apply).and_call_original
25
- end
26
-
27
- it 'auth works with real requests' do
28
- expect{ api.get('/files/') }.not_to raise_error
29
- end
30
- end
31
- end
@@ -1,75 +0,0 @@
1
- require 'spec_helper'
2
- require 'uri'
3
- require 'socket'
4
-
5
- describe Uploadcare::Error do
6
- before(:all) do
7
- @settings = Uploadcare.default_settings
8
- @codes = [400,401,403,404,406,408,422,429,500,502,503,504]
9
- @connection = Uploadcare::Connections::ApiConnection.new(@settings)
10
- end
11
-
12
- it 'Error codes should be accesbile' do
13
- Uploadcare::Error.errors.keys.should == @codes
14
- end
15
-
16
- it 'Errors should be kind of requested codes' do
17
- not_found = Uploadcare::Error.errors[404]
18
- not_found.new('File not found').should be_kind_of(Uploadcare::Error::RequestError::NotFound)
19
- end
20
-
21
- it 'errors should have meaningfull messages' do
22
- not_found = Uploadcare::Error.errors[404]
23
- error = not_found.new
24
- error.message.should == "HTTP 404 - the requested resource could not be found."
25
- end
26
-
27
- it 'Should raise an error' do
28
- error = Uploadcare::Error::RequestError::NotFound
29
- expect{ @connection.send :get, '/random_url/', {} }.to raise_error(error)
30
- end
31
-
32
- it "should escape particular error" do
33
- error = Uploadcare::Error::RequestError::NotFound
34
- expect do
35
- begin
36
- @connection.send :get, '/random_url/', {}
37
- rescue error => e
38
- nil
39
- end
40
- end.to_not raise_error
41
- end
42
-
43
- it 'should escape common request error' do
44
- error = Uploadcare::Error::RequestError
45
- expect do
46
- begin
47
- @connection.send :get, '/random_url/', {}
48
- rescue error => e
49
- nil
50
- end
51
- end.to_not raise_error
52
- end
53
-
54
- it 'should escape generic uploadcare service error' do
55
- error = Uploadcare::Error
56
- expect do
57
- begin
58
- @connection.send :get, '/random_url/', {}
59
- rescue error => e
60
- nil
61
- end
62
- end.to_not raise_error
63
- end
64
-
65
- it 'should escape generic uploadcare service error' do
66
- error = StandardError
67
- expect do
68
- begin
69
- @connection.send :get, '/random_url/', {}
70
- rescue error => e
71
- nil
72
- end
73
- end.to_not raise_error
74
- end
75
- end
@@ -1,19 +0,0 @@
1
- require 'spec_helper'
2
- require 'uri'
3
- require 'socket'
4
-
5
- describe Uploadcare::Connections::UploadConnection do
6
- before(:all) do
7
- @settings = Uploadcare.default_settings
8
- end
9
-
10
- it 'should initialize upload connection' do
11
- expect {Uploadcare::Connections::UploadConnection.new(@settings)}.to_not raise_error
12
- end
13
-
14
- it 'should use ParseJson and RaiseError middleware' do
15
- connection = Uploadcare::Connections::UploadConnection.new(@settings)
16
- connection.builder.handlers.include?(Uploadcare::Connections::Response::ParseJson).should == true
17
- connection.builder.handlers.include?(Uploadcare::Connections::Response::RaiseError).should == true
18
- end
19
- end
@@ -1,188 +0,0 @@
1
- require 'spec_helper'
2
-
3
- shared_examples 'resource list' do
4
- describe '#options' do
5
- subject{ @list.options }
6
-
7
- it{ is_expected.to be_a(Hash) }
8
- it{ is_expected.to be_frozen }
9
-
10
- it 'stores options' do
11
- expect( subject ).to eq(limit: 1)
12
- end
13
- end
14
-
15
- describe '#meta' do
16
- subject{ @list.meta }
17
-
18
- it{ is_expected.to be_a(Hash) }
19
- it{ is_expected.to be_frozen }
20
- end
21
-
22
- describe '#total' do
23
- subject{ @list.total }
24
-
25
- it{ is_expected.to be_an(Integer) }
26
-
27
- it 'returns a "total" value from metadata' do
28
- expect( subject ).to eq @list.meta["total"]
29
- end
30
- end
31
-
32
- describe '#loaded' do
33
- subject{ @list.loaded }
34
-
35
- it{ is_expected.to be_an(Integer) }
36
-
37
- it 'contains currently loaded objects count' do
38
- size = rand(2..10)
39
- allow(@list).to receive(:objects){ Array.new(size) }
40
-
41
- expect( subject ).to eq(size)
42
- end
43
- end
44
-
45
- describe '#fully_loaded?' do
46
- subject{ @list.fully_loaded? }
47
-
48
- context 'if there is no more next pages left' do
49
- before { allow(@list).to receive(:meta){ {"next" => nil} } }
50
- it { is_expected.to be_truthy }
51
- end
52
-
53
- context 'if there is a next page' do
54
- before { allow(@list).to receive(:meta){ {"next" => 'example.com'} } }
55
- it { is_expected.to be_falsey }
56
- end
57
- end
58
-
59
- describe '#each' do
60
- it 'when called without a block, returns an Enumerator' do
61
- expect( subject.each ).to be_an(Enumerator)
62
- end
63
-
64
- it 'when called with a block, returns self' do
65
- allow(subject).to receive(:meta){ {"next" => nil} }
66
- expect( subject.each{|o| nil } ).to eq(subject)
67
- end
68
-
69
- it 'when called with a break inside a block, returns nil' do
70
- expect( subject.each{|o| break } ).to be_nil
71
- end
72
- end
73
-
74
- describe '#[]' do
75
- subject{ @list.dup }
76
-
77
- it "returns instances of a resource class" do
78
- expect( subject[0] ).to be_a(resource_class)
79
- end
80
-
81
- it 'loads additional objects when needed' do
82
- expect(@api).to receive(:get)
83
- .with(subject.meta["next"]).and_call_original
84
-
85
- expect { subject[1] }.to change { subject.objects.size }.by(1)
86
- end
87
- end
88
-
89
- describe 'enumerable interface' do
90
- subject{ @list.dup }
91
-
92
- it 'is an Enumerable' do
93
- expect( subject ).to be_an(Enumerable)
94
- end
95
-
96
- it 'iterates through objects' do
97
- i, uuids = 0, []
98
- subject.each{|object| uuids << object.uuid; i+=1; break if i >= 2 }
99
-
100
- expect(uuids).to eq([subject[0].uuid, subject[1].uuid])
101
- end
102
-
103
- it 'loads additional objects when needed' do
104
- expect(@api).to receive(:get)
105
- .with(subject.meta["next"]).and_call_original
106
-
107
- objects = subject.first(2)
108
-
109
- expect(objects.size).to eq(2)
110
- end
111
-
112
- it 'doesn\'t load more objects than needed' do
113
- expect(@api).to receive(:get).once.and_call_original
114
-
115
- objects = subject.first(2)
116
-
117
- expect(objects.size).to eq(2)
118
- end
119
-
120
- it "loads different objects" do
121
- expect(@api).to receive(:get)
122
- .with(subject.meta["next"]).and_call_original
123
-
124
- objects = subject.first(2)
125
-
126
- expect(objects[0].uuid).not_to eq(objects[1].uuid)
127
- end
128
-
129
- it 'stops loading objects when no objects left' do
130
- allow(@api).to receive(:get).and_wrap_original do |m, *args|
131
- m.call(*args).tap{|data| data["next"] = nil}
132
- end
133
-
134
- uuids = subject.map{|object| object.uuid}
135
-
136
- expect( uuids.size ).to eq(2)
137
- end
138
-
139
- it 'preserves loaded objects' do
140
- expect( subject.loaded ).to eq(1)
141
-
142
- subject.first(2)
143
-
144
- expect( subject.loaded ).to eq(2)
145
- end
146
-
147
- it 'updates #meta with data from last api response' do
148
- new_meta = {}
149
- allow(@api).to receive(:get).and_wrap_original do |m, *args|
150
- m.call(*args).tap{|data| new_meta = data.reject{|k,_| k == "results"}}
151
- end
152
-
153
- subject.first(2)
154
-
155
- expect( subject.meta ).to eq(new_meta)
156
- end
157
-
158
- if Gem.ruby_version >= Gem::Version.new('2.0.0')
159
- context 'when lazy enumerator is used' do
160
- it 'preserves loaded objects' do
161
- expect(subject.loaded).to eq 1
162
-
163
- subject.lazy.first(2)
164
-
165
- expect(subject.loaded).to eq 2
166
- end
167
- end
168
- end
169
-
170
- context 'when a block passed to an enumerator method contains a break' do
171
- it 'preserves loaded objects' do
172
- i = 0
173
- subject.each{|o| i+= 1; break if i >= 2}
174
-
175
- expect( subject.loaded ).to eq(2)
176
- end
177
- end
178
-
179
- context 'when a block passed to an enumerator method raises an exception' do
180
- it 'preserves loaded objects' do
181
- i = 0
182
- subject.each{|o| i += 1; raise if i>= 2} rescue nil
183
-
184
- expect( subject.loaded ).to eq(2)
185
- end
186
- end
187
- end
188
- end