resync-client 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6dc391cfdfcafd5a808a5a4736daf19a1e52d418
4
- data.tar.gz: 2f983d3560d4bf3390faaeda241e5b6a570be8f9
3
+ metadata.gz: f400045ef45597f5b91078336f0210322b58ff29
4
+ data.tar.gz: c6f10cbd9a55a03e7b2d9c7db1f5bd721189acff
5
5
  SHA512:
6
- metadata.gz: 65e5d83731a97afab8e3d1d6cbcca7ef716f7acf2e3e7d1ef490763dff15c8daef6539591bd51069b11ddae2f530bcd005928e92b57fdd0805b092e66da7b961
7
- data.tar.gz: 468e546e76abb8f29ca6f6a968efd17ab46f785fd082148f0b9b343fca139a69cc2f9dcbd0f491ad37834dab454d104fae35edca5f0e055fcbcba0f34558effc
6
+ metadata.gz: 561e1fc1d2c34e59a31ace3f76ae1522839500a65a8b6f6a407654ee32b91f7ded1cba8b07e8550932b03e2f6dff983205b9d51ba7042689aca1f897772dbd9a
7
+ data.tar.gz: 327fe3b46728b19e6043f78f363df94d1d4a74b21c3363fa70d8f720c02ce500f5bf2e188bf96cb8c16bfdd3b61ed2ef0847d1888a1e9eb2279940cbae34cba8
data/.travis.yml CHANGED
@@ -1,2 +1,7 @@
1
1
  language: ruby
2
2
 
3
+ addons:
4
+ code_climate:
5
+ repo_token: dbb3c6eb70c0de106cdc3f65d542882e7bfce9deee2db544dbcc7ca0a4e5f3da
6
+
7
+
data/CHANGES.md CHANGED
@@ -1,3 +1,15 @@
1
+ # 0.3.0
2
+
3
+ - Update to depend on [resync](https://github.com/dmolesUC3/resync) 0.3.0
4
+ - Replace `ZipPackages` class with simple enumerable
5
+
6
+ # 0.2.6
7
+
8
+ - Added `#all_resources` (as alias for `#resources`) to `ChangeList`/`ResourceList` for transparent interoperability with `ChangeListIndex`/`ResourceListIndex`
9
+ - Added `#all_changes` (as alias for `#changes`) to `ChangeList`/`ChangeDump` for transparent interoperability with `ChangeListIndex`/`ChangeDumpIndex`
10
+ <!-- TODO: figure out what ChangeDump#all_changes should really do -->
11
+ - Added `#all_zip_packages` (as alias for `#zip_packages`) to `ChangeDump`/`ResourceDump` for transparent interoperability with `ChangeDumpIndex`/`ResourceDumpIndex`
12
+
1
13
  # 0.2.5
2
14
 
3
15
  - Added `#all_changes` to transparently download and flatten changes in `ChangeListIndex` and `ChangeDumpIndex` documents, with filtering by time and type
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # resync-client
1
+ # resync-client [![Build Status](https://travis-ci.org/dmolesUC3/resync-client.png?branch=master)](https://travis-ci.org/dmolesUC3/resync-client) [![Code Climate](https://codeclimate.com/github/dmolesUC3/resync-client.png)](https://codeclimate.com/github/dmolesUC3/resync-client) [![Inline docs](http://inch-ci.org/github/dmolesUC3/resync-client.png)](http://inch-ci.org/github/dmolesUC3/resync-client)
2
2
 
3
3
  A gem providing a Ruby client for the [ResourceSync](http://www.openarchives.org/rs/1.0/resourcesync) web synchronization framework, based on the [resync](https://github.com/dmolesUC3/resync) gem and [Net::HTTP](http://ruby-doc.org/stdlib-2.2.2/libdoc/net/http/rdoc/Net/HTTP.html).
4
4
 
@@ -34,4 +34,10 @@ module Resync
34
34
  class BaseChangeIndex
35
35
  prepend Client::Mixins::ChangeIndex
36
36
  end
37
+
38
+ class ChangeList
39
+ # Aliases +:changes+ as +:all_changes+ for transparent
40
+ # interoperability with +ChangeListIndex+
41
+ alias_method :all_changes, :changes
42
+ end
37
43
  end
@@ -1,4 +1,5 @@
1
1
  require 'resync'
2
+ require 'lazy'
2
3
  require_relative '../zip'
3
4
  require_relative 'zipped_resource'
4
5
 
@@ -7,6 +8,8 @@ module Resync
7
8
  module Mixins
8
9
  # A list of resources each of which refers to a zipped bitstream package.
9
10
  module Dump
11
+
12
+ # Makes each resource a {ZippedResource}
10
13
  def resources=(value)
11
14
  super
12
15
  resources.each do |r|
@@ -17,11 +20,19 @@ module Resync
17
20
  end
18
21
  end
19
22
 
20
- # A list (downloaded lazily) of the {Resync::Client::Zip::ZipPackage}s for each resource
21
- # @return [Resync::Client::Zip::ZipPackages] the zip packages for each resource
23
+ # The {Resync::Client::Zip::ZipPackage}s for each resource, downloaded lazily
24
+ # @return [Array<Lazy::Promise<Resync::Client::Zip::ZipPackage>>] the zip packages for each resource
22
25
  def zip_packages
23
- @zip_packages ||= Resync::Client::Zip::ZipPackages.new(resources)
26
+ @zip_packages ||= resources.map { |r| Lazy.promise { r.zip_package } }
27
+ end
28
+
29
+ # Aliases +:zip_packages+ as +:all_zip_packages+ for transparent
30
+ # interoperability between +ResourceDump+ and +ResourceDumpIndex+,
31
+ # +ChangeDump+ and +ChangeDumpIndex+
32
+ def self.prepended(ext)
33
+ ext.send(:alias_method, :all_zip_packages, :zip_packages)
24
34
  end
35
+
25
36
  end
26
37
  end
27
38
  end
@@ -31,6 +42,23 @@ module Resync
31
42
  end
32
43
 
33
44
  class ChangeDump
34
- prepend Client::Mixins::Dump
45
+ include Client::Mixins::Dump
46
+
47
+ # A list (downloaded lazily) of the {Resync::Client::Zip::ZipPackage}s for each resource
48
+ # If a time range parameter is provided, the lists of packages is filtered by +from_time+
49
+ # and +until_time+, in non-strict mode (only excluding those lists provably not in the range,
50
+ # i.e., including packages without +from_time+ or +until_time+).
51
+ # @param in_range [Range<Time>] the range of times to filter by
52
+ # @return [Array<Lazy::Promise<Resync::Client::Zip::ZipPackage>>] the zip packages for each resource
53
+ def zip_packages(in_range: nil)
54
+ if in_range
55
+ change_lists = change_lists(in_range: in_range, strict: false)
56
+ change_lists.map { |r| Lazy.promise { r.zip_package } }
57
+ else
58
+ super()
59
+ end
60
+ end
61
+
62
+ alias_method :all_zip_packages, :zip_packages
35
63
  end
36
64
  end
@@ -11,20 +11,54 @@ module Resync
11
11
  # Downloads and parses each resource list and returns a flattened enumeration
12
12
  # of all zip packages in each contained list. Each contained list is only downloaded
13
13
  # as needed, and only downloaded once.
14
- # @return [Enumerator::Lazy<Resync::Client::Zip::ZipPackages>] the flattened enumeration of resources
14
+ # @return [Enumerator::Lazy<Resync::Client::Zip::ZipPackage>] the flattened enumeration of resources
15
15
  def all_zip_packages
16
- @zipped_resource_lists ||= {}
17
- resources.flat_map do |r|
18
- @zipped_resource_lists[r] ||= r.get_and_parse
19
- @zipped_resource_lists[r].respond_to?(:zip_packages) ? @zipped_resource_lists[r].zip_packages : []
16
+ resources.lazy.flat_map do |r|
17
+ package_for(r)
20
18
  end
21
19
  end
20
+
21
+ private
22
+
23
+ def zipped_resource_list_for(r)
24
+ @zipped_resource_lists ||= {}
25
+ @zipped_resource_lists[r] ||= r.get_and_parse
26
+ end
27
+
28
+ def package_for(r)
29
+ zrl = zipped_resource_list_for(r)
30
+ zrl.respond_to?(:zip_packages) ? zrl.zip_packages : []
31
+ end
22
32
  end
23
33
  end
24
34
  end
25
35
 
26
36
  class ChangeDumpIndex
27
- prepend Client::Mixins::DumpIndex
37
+ include Client::Mixins::DumpIndex
38
+
39
+ # Downloads and parses each resource list and returns a flattened enumeration
40
+ # of all zip packages in each contained list. Each contained list is only downloaded
41
+ # as needed, and only downloaded once.
42
+ # If a time range parameter is provided, the lists of packages is filtered by +from_time+
43
+ # and +until_time+, in non-strict mode (only excluding those lists provably not in the range,
44
+ # i.e., including packages without +from_time+ or +until_time+).
45
+ # @param in_range [Range<Time>] the range of times to filter by
46
+ # @return [Enumerator::Lazy<Resync::Client::Zip::ZipPackage>] the flattened enumeration of resources
47
+ def all_zip_packages(in_range: nil)
48
+ if in_range
49
+ dump_resources = change_lists(in_range: in_range, strict: false)
50
+ dump_resources.lazy.flat_map { |cl| package_for(cl, in_range: in_range) }
51
+ else
52
+ super()
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def package_for(r, in_range: nil)
59
+ zrl = zipped_resource_list_for(r)
60
+ in_range ? zrl.zip_packages(in_range: in_range) : super(r)
61
+ end
28
62
  end
29
63
 
30
64
  class ResourceDumpIndex
@@ -14,7 +14,7 @@ module Resync
14
14
  # @return [Enumerator::Lazy<Resync::Resource>] the flattened enumeration of resources
15
15
  def all_resources
16
16
  @resource_lists ||= {}
17
- resources.flat_map do |r|
17
+ resources.lazy.flat_map do |r|
18
18
  @resource_lists[r] ||= r.get_and_parse
19
19
  @resource_lists[r].resources
20
20
  end
@@ -27,7 +27,19 @@ module Resync
27
27
  prepend Client::Mixins::ListIndex
28
28
  end
29
29
 
30
+ class ChangeList
31
+ # Aliases +:resources+ as +:all_resources+ for transparent
32
+ # interoperability with +ChangeListIndex+
33
+ alias_method :all_resources, :resources
34
+ end
35
+
30
36
  class ResourceListIndex
31
37
  prepend Client::Mixins::ListIndex
32
38
  end
39
+
40
+ class ResourceList
41
+ # Aliases +:resources+ as +:all_resources+ for transparent
42
+ # interoperability with +ResourceListIndex+
43
+ alias_method :all_resources, :resources
44
+ end
33
45
  end
@@ -1,6 +1,6 @@
1
1
  module Resync
2
2
  class Client
3
3
  # The version of this gem.
4
- VERSION = '0.2.5'
4
+ VERSION = '0.3.0'
5
5
  end
6
6
  end
@@ -22,7 +22,8 @@ Gem::Specification.new do |spec|
22
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
23
  spec.require_paths = ['lib']
24
24
 
25
- spec.add_dependency 'resync', '~> 0.2', '>= 0.2.2'
25
+ spec.add_dependency 'lazy', '~> 0.9', '>= 0.9.6'
26
+ spec.add_dependency 'resync', '~> 0.2', '>= 0.3.0'
26
27
  spec.add_dependency 'rubyzip', '~> 1.1'
27
28
 
28
29
  spec.add_development_dependency 'equivalent-xml', '~> 0.6.0'
@@ -32,4 +33,5 @@ Gem::Specification.new do |spec|
32
33
  spec.add_development_dependency 'simplecov', '~> 0.9.2'
33
34
  spec.add_development_dependency 'simplecov-console', '~> 0.2.0'
34
35
  spec.add_development_dependency 'yard', '~> 0.8'
36
+ spec.add_development_dependency 'codeclimate-test-reporter', '~> 0'
35
37
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  # ------------------------------------------------------------
2
- # SimpleCov setup
2
+ # SimpleCov/CodeClimate setup
3
3
 
4
4
  if ENV['COVERAGE']
5
+ if ENV['CODECLIMATE_REPO_TOKEN']
6
+ require 'codeclimate-test-reporter'
7
+ CodeClimate::TestReporter.start
8
+ end
9
+
5
10
  require 'simplecov'
6
11
  require 'simplecov-console'
7
12
 
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ module Resync
4
+ describe ChangeDumpIndex do
5
+ before(:each) do
6
+ @change_dump_index = ChangeDumpIndex.load_from_xml(XML.element(
7
+ "<sitemapindex xmlns='http://www.sitemaps.org/schemas/sitemap/0.9' xmlns:rs='http://www.openarchives.org/rs/terms/'>
8
+ <rs:md capability='changedump'/>
9
+ <sitemap>
10
+ <loc>http://example.com/20130101-changedump.xml</loc>
11
+ <rs:md from='2013-01-01T00:00:00Z' until='2013-01-02T00:00:00Z'/>
12
+ </sitemap>
13
+ <sitemap>
14
+ <loc>http://example.com/20130102-changedump.xml</loc>
15
+ <rs:md from='2013-01-02T00:00:00Z' until='2013-01-03T00:00:00Z'/>
16
+ </sitemap>
17
+ <sitemap>
18
+ <loc>http://example.com/20130103-changedump.xml</loc>
19
+ <rs:md from='2013-01-03T00:00:00Z' until='2013-01-04T00:00:00Z'/>
20
+ </sitemap>
21
+ </sitemapindex>"))
22
+
23
+ @change_dumps = [
24
+ "<urlset xmlns='http://www.sitemaps.org/schemas/sitemap/0.9' xmlns:rs='http://www.openarchives.org/rs/terms/'>
25
+ <rs:md capability='changedump'/>
26
+ <url>
27
+ <loc>http://example.com/20130101-changedump-0.zip</loc>
28
+ <rs:md modified='2013-01-01T11:59:59Z' from='2013-01-01T00:00:00Z' until='2013-01-01T12:00:00Z'/>
29
+ </url>
30
+ <url>
31
+ <loc>http://example.com/20130101-changedump-1.zip</loc>
32
+ <rs:md modified='2013-01-01T23:59:59Z' from='2013-01-01T12:00:00Z' until='2013-01-02T00:00:00Z'/>
33
+ </url>
34
+ </urlset>",
35
+ "<urlset xmlns='http://www.sitemaps.org/schemas/sitemap/0.9' xmlns:rs='http://www.openarchives.org/rs/terms/'>
36
+ <rs:md capability='changedump'/>
37
+ <url>
38
+ <loc>http://example.com/20130102-changedump-0.zip</loc>
39
+ <rs:md modified='2013-01-02T11:59:59Z' from='2013-01-02T00:00:00Z' until='2013-01-02T12:00:00Z'/>
40
+ </url>
41
+ <url>
42
+ <loc>http://example.com/20130102-changedump-1.zip</loc>
43
+ <rs:md modified='2013-01-02T23:59:59Z' from='2013-01-02T12:00:00Z' until='2013-01-03T00:00:00Z'/>
44
+ </url>
45
+ </urlset>",
46
+ "<urlset xmlns='http://www.sitemaps.org/schemas/sitemap/0.9' xmlns:rs='http://www.openarchives.org/rs/terms/'>
47
+ <rs:md capability='changedump'/>
48
+ <url>
49
+ <loc>http://example.com/20130103-changedump-0.zip</loc>
50
+ <rs:md modified='2013-01-03T11:59:59Z' from='2013-01-03T00:00:00Z' until='2013-01-03T12:00:00Z'/>
51
+ </url>
52
+ <url>
53
+ <loc>http://example.com/20130103-changedump-1.zip</loc>
54
+ <rs:md modified='2013-01-03T23:59:59Z' from='2013-01-03T12:00:00Z' until='2013-01-04T00:00:00Z'/>
55
+ </url>
56
+ </urlset>"
57
+ ].map { |xml| ChangeDump.load_from_xml(XML.element(xml)) }
58
+
59
+ @all_package_resources = []
60
+ @all_zip_packages = []
61
+ @change_dumps.each do |d|
62
+ d.resources.each do |r|
63
+ @all_package_resources << r
64
+ zp = instance_double(Resync::Client::Zip::ZipPackage)
65
+ allow(r).to receive(:zip_package) { zp }
66
+ @all_zip_packages << zp
67
+ end
68
+ end
69
+
70
+ @change_dump_resources = []
71
+ @change_dump_index.resources.each_with_index do |r, i|
72
+ @change_dump_resources << r
73
+ allow(r).to receive(:get_and_parse) { @change_dumps[i] }
74
+ end
75
+ end
76
+
77
+ describe '#all_zip_packages' do
78
+ it 'should accept an optional time range' do
79
+ range = Time.utc(2013, 1, 1)..Time.utc(2013, 1, 2, 6)
80
+ all_packages = @change_dump_index.all_zip_packages(in_range: range).to_a
81
+ expect(all_packages).to eq(@all_zip_packages[0, 3])
82
+ end
83
+
84
+ it 'should not download unnecessary dumps or packages' do
85
+ expect(@change_dump_resources[2]).not_to receive(:get_and_parse)
86
+ @all_package_resources[3, 3].each do |r|
87
+ expect(r).not_to receive(:zip_package)
88
+ end
89
+ @change_dump_index.all_zip_packages(in_range: Time.utc(2013, 1, 1)..Time.utc(2013, 1, 2, 6)).to_a
90
+ end
91
+
92
+ it 'should not require a time range' do
93
+ all_packages = @change_dump_index.all_zip_packages.to_a
94
+ expect(all_packages).to eq(@all_zip_packages)
95
+ end
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ module Resync
4
+ describe ChangeDump do
5
+ before(:each) do
6
+ @resources = [
7
+ Resource.new(
8
+ uri: URI('http://example.com/20130101-changedump.zip'),
9
+ modified_time: Time.utc(2013, 1, 1, 23, 59, 59),
10
+ metadata: Metadata.new(
11
+ from_time: Time.utc(2013, 1, 1),
12
+ until_time: Time.utc(2013, 1, 2))),
13
+ Resource.new(
14
+ uri: URI('http://example.com/20130102-changedump.zip'),
15
+ modified_time: Time.utc(2013, 1, 2, 23, 59, 59),
16
+ metadata: Metadata.new(
17
+ from_time: Time.utc(2013, 1, 2),
18
+ until_time: Time.utc(2013, 1, 3))),
19
+ Resource.new(
20
+ uri: URI('http://example.com/20130103-changedump.zip'),
21
+ modified_time: Time.utc(2013, 1, 3, 23, 59, 59),
22
+ metadata: Metadata.new(
23
+ from_time: Time.utc(2013, 1, 3),
24
+ until_time: Time.utc(2013, 1, 4)))
25
+ ]
26
+ @dump = ChangeDump.new(resources: @resources)
27
+
28
+ @zip_packages = []
29
+ @resources.each_with_index do |r, i|
30
+ @zip_packages[i] = instance_double(Resync::Client::Zip::ZipPackage)
31
+ allow(r).to receive(:zip_package) { @zip_packages[i] }
32
+ end
33
+ end
34
+
35
+ describe '#zip_packages' do
36
+ it 'should accept an optional time range' do
37
+ packages = @dump.zip_packages(in_range: Time.utc(2013, 1, 3)..Time.utc(2013, 1, 4))
38
+ expect(packages.size).to eq(2)
39
+ expect(packages.to_a).to eq([@zip_packages[1], @zip_packages[2]])
40
+ end
41
+
42
+ it 'should not require a time range' do
43
+ packages = @dump.zip_packages
44
+ expect(packages.to_a).to eq(@zip_packages)
45
+ end
46
+ end
47
+
48
+ describe '#all_zip_packages' do
49
+ it 'should delegate to #zip_packages' do
50
+ packages = @dump.all_zip_packages
51
+ expect(packages.to_a).to eq(@zip_packages)
52
+ end
53
+ end
54
+ end
55
+
56
+ end
@@ -51,10 +51,14 @@ module Resync
51
51
 
52
52
  it 'is lazy enough not to download resources it doesn\'t need' do
53
53
  resources = Array.new(3) { instance_double(ZippedResource) }
54
- resources.each do |r|
54
+ zip_packages = Array.new(3) { instance_double(Zip::ZipPackage) }
55
+ resources.each_with_index do |r, i|
55
56
  allow(r).to receive(:client_delegate=)
56
- zip_package = instance_double(Zip::ZipPackage)
57
- expect(r).to receive(:zip_package).once.and_return(zip_package)
57
+ if i <= 1
58
+ expect(r).to receive(:zip_package).once.and_return(zip_packages[i])
59
+ else
60
+ expect(r).not_to receive(:zip_package)
61
+ end
58
62
  end
59
63
 
60
64
  dump1 = ResourceDump.new(resources: resources[0, 3])
@@ -68,37 +72,9 @@ module Resync
68
72
  expect(dump2_resource).not_to receive(:get_and_parse)
69
73
 
70
74
  index = ResourceDumpIndex.new(resources: [dump1_resource, dump2_resource])
71
- index.all_zip_packages.each_with_index do |_, i|
72
- break if i >= 2
73
- end
74
- end
75
-
76
- it 'caches downloaded resources' do
77
- resources = Array.new(6) { instance_double(ZippedResource) }
78
- resources.each do |r|
79
- allow(r).to receive(:client_delegate=)
80
- zip_package = instance_double(Zip::ZipPackage)
81
- expect(r).to receive(:zip_package).once.and_return(zip_package)
82
- end
83
-
84
- dump1 = ResourceDump.new(resources: resources[0, 3])
85
- dump2 = ResourceDump.new(resources: resources[3, 3])
86
-
87
- dump1_resource = instance_double(Resource)
88
- allow(dump1_resource).to receive(:client_delegate=)
89
- expect(dump1_resource).to receive(:get_and_parse).once.and_return(dump1)
90
-
91
- dump2_resource = instance_double(Resource)
92
- allow(dump2_resource).to receive(:client_delegate=)
93
- expect(dump2_resource).to receive(:get_and_parse).once.and_return(dump2)
94
-
95
- index = ResourceDumpIndex.new(resources: [dump1_resource, dump2_resource])
96
- all_packages = index.all_zip_packages
97
-
98
- a1 = all_packages.to_a
99
- a2 = all_packages.to_a
100
- a1.each_with_index do |pkg, i|
101
- expect(pkg).to be(a2[i])
75
+ index.all_zip_packages.each_with_index do |zp, i|
76
+ expect(zp).to be(zip_packages[i])
77
+ break if i >= 1
102
78
  end
103
79
  end
104
80
  end
@@ -1,60 +1,205 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Resync
4
- class Client
5
- module Mixins
6
- describe Dump do
7
- it "works for #{ResourceDump}" do
8
- path = 'spec/data/resourcedump/resourcedump.xml'
9
- package_uri = URI('http://example.com/resourcedump.zip')
4
+ # TODO: introduce shared examples
5
+ describe ResourceDump do
6
+ describe '#zip_packages' do
7
+ it 'transparently exposes bitstreams' do
8
+ path = 'spec/data/resourcedump/resourcedump.xml'
9
+ package_uri = URI('http://example.com/resourcedump.zip')
10
+
11
+ client = instance_double(Client)
12
+ expect(client).to receive(:download_to_temp_file).once.with(package_uri).and_return('spec/data/resourcedump/resourcedump.zip')
13
+
14
+ dump = XMLParser.parse(File.read(path))
15
+ dump.client = client
16
+
17
+ zip_packages = dump.zip_packages
18
+ expect(zip_packages.size).to eq(1)
19
+ expect(zip_packages[0]).to be_a(Client::Zip::ZipPackage)
20
+
21
+ bitstreams = zip_packages[0].bitstreams
22
+ expect(bitstreams.size).to eq(2)
23
+ expect(bitstreams[0].content).to eq(File.read('spec/data/resourcedump/resources/res1'))
24
+ expect(bitstreams[1].content).to eq(File.read('spec/data/resourcedump/resources/res2'))
25
+ end
26
+
27
+ it 'is lazy' do
28
+ resources = Array.new(3) { |i| Resource.new(uri: "http://example.org/res#{i}") }
29
+ dump = ResourceDump.new(resources: resources)
30
+ zip_packages = dump.zip_packages
31
+ zip_package = instance_double(Client::Zip::ZipPackage)
10
32
 
11
- client = instance_double(Client)
12
- expect(client).to receive(:download_to_temp_file).once.with(package_uri).and_return('spec/data/resourcedump/resourcedump.zip')
33
+ expect(resources[0]).not_to receive(:zip_package)
34
+ expect(resources[1]).not_to receive(:zip_package)
35
+ expect(resources[2]).to receive(:zip_package).and_return(zip_package)
13
36
 
14
- dump = XMLParser.parse(File.read(path))
15
- dump.client = client
37
+ expect(zip_packages[2]).to be(zip_package)
38
+ end
39
+
40
+ it 'flatmaps' do
41
+ resources = Array.new(6) { |i| Resource.new(uri: "http://example.org/res#{i}") }
42
+ all_packages = Array.new(6) do |i|
43
+ zip_package = instance_double(Client::Zip::ZipPackage)
44
+ expect(resources[i]).to receive(:zip_package).once.and_return(zip_package)
45
+ zip_package
46
+ end
16
47
 
17
- zip_packages = dump.zip_packages
18
- expect(zip_packages.size).to eq(1)
48
+ zrl1 = ResourceDump.new(resources: resources[0, 3])
49
+ zrl2 = ResourceDump.new(resources: resources[3, 3])
19
50
 
20
- zip_package = zip_packages[0]
21
- expect(zip_package).to be_a(Resync::Client::Zip::ZipPackage)
51
+ flat_mapped = [zrl1, zrl2].flat_map(&:zip_packages)
52
+ expect(flat_mapped).to eq(all_packages)
22
53
 
23
- bitstreams = zip_package.bitstreams
24
- expect(bitstreams.size).to eq(2)
54
+ lazy_flat_mapped = [zrl1, zrl2].lazy.flat_map(&:zip_packages).to_a
55
+ expect(lazy_flat_mapped).to eq(all_packages)
56
+ end
25
57
 
26
- stream1 = bitstreams[0]
27
- expect(stream1.content).to eq(File.read('spec/data/resourcedump/resources/res1'))
58
+ it 'supports lazy iteration 'do
59
+ manifests = Array.new(3) { instance_double(ChangeDumpManifest) }
60
+ all_packages = Array.new(3) do |index|
61
+ zip_package = instance_double(Client::Zip::ZipPackage)
62
+ allow(zip_package).to receive(:manifest).and_return(manifests[index])
63
+ zip_package
64
+ end
65
+ resources = Array.new(3) do |index|
66
+ resource = Resource.new(uri: "http://example.org/res#{index}")
67
+ if index > 1
68
+ expect(resource).not_to receive(:zip_package)
69
+ else
70
+ expect(resource).to receive(:zip_package).and_return(all_packages[index])
71
+ end
72
+ resource
73
+ end
28
74
 
29
- stream2 = bitstreams[1]
30
- expect(stream2.content).to eq(File.read('spec/data/resourcedump/resources/res2'))
75
+ zip_packages = ResourceDump.new(resources: resources).zip_packages
76
+ zip_packages.each_with_index do |zip_package, index|
77
+ expect(zip_package.manifest).to be(manifests[index])
78
+ break if index >= 1
31
79
  end
80
+ end
81
+ end
32
82
 
33
- it "works for #{ChangeDump}" do
34
- path = 'spec/data/resourcedump/changedump.xml'
35
- package_uri = URI('http://example.com/changedump.zip')
83
+ describe '#all_zip_packages' do
84
+ it 'is an alias for #zip_packages' do
85
+ path = 'spec/data/resourcedump/resourcedump.xml'
86
+ package_uri = URI('http://example.com/resourcedump.zip')
36
87
 
37
- client = instance_double(Client)
38
- expect(client).to receive(:download_to_temp_file).once.with(package_uri).and_return('spec/data/resourcedump/resourcedump.zip')
88
+ client = instance_double(Client)
89
+ expect(client).to receive(:download_to_temp_file).once.with(package_uri).and_return('spec/data/resourcedump/resourcedump.zip')
39
90
 
40
- dump = XMLParser.parse(File.read(path))
41
- dump.client = client
91
+ dump = XMLParser.parse(File.read(path))
92
+ dump.client = client
42
93
 
43
- zip_packages = dump.zip_packages
44
- expect(zip_packages.size).to eq(1)
94
+ all_zip_packages = dump.all_zip_packages
95
+ expect(all_zip_packages.size).to eq(1)
96
+ expect(all_zip_packages[0]).to be_a(Client::Zip::ZipPackage)
45
97
 
46
- zip_package = zip_packages[0]
47
- expect(zip_package).to be_a(Resync::Client::Zip::ZipPackage)
98
+ bitstreams = all_zip_packages[0].bitstreams
99
+ expect(bitstreams.size).to eq(2)
100
+ expect(bitstreams[0].content).to eq(File.read('spec/data/resourcedump/resources/res1'))
101
+ expect(bitstreams[1].content).to eq(File.read('spec/data/resourcedump/resources/res2'))
102
+ end
103
+ end
104
+ end
105
+
106
+ describe ChangeDump do
107
+ describe '#zip_packages' do
108
+ it 'transparently exposes bitstreams' do
109
+ path = 'spec/data/resourcedump/changedump.xml'
110
+ package_uri = URI('http://example.com/changedump.zip')
111
+
112
+ client = instance_double(Client)
113
+ expect(client).to receive(:download_to_temp_file).once.with(package_uri).and_return('spec/data/resourcedump/resourcedump.zip')
114
+
115
+ dump = XMLParser.parse(File.read(path))
116
+ dump.client = client
117
+
118
+ zip_packages = dump.zip_packages
119
+ expect(zip_packages.size).to eq(1)
120
+ expect(zip_packages[0]).to be_a(Client::Zip::ZipPackage)
121
+
122
+ bitstreams = zip_packages[0].bitstreams
123
+ expect(bitstreams.size).to eq(2)
124
+ expect(bitstreams[0].content).to eq(File.read('spec/data/resourcedump/resources/res1'))
125
+ expect(bitstreams[1].content).to eq(File.read('spec/data/resourcedump/resources/res2'))
126
+ end
48
127
 
49
- bitstreams = zip_package.bitstreams
50
- expect(bitstreams.size).to eq(2)
128
+ it 'is lazy' do
129
+ resources = Array.new(3) { |i| Resource.new(uri: "http://example.org/res#{i}") }
130
+ dump = ChangeDump.new(resources: resources)
131
+ zip_packages = dump.zip_packages
132
+ zip_package = instance_double(Client::Zip::ZipPackage)
51
133
 
52
- stream1 = bitstreams[0]
53
- expect(stream1.content).to eq(File.read('spec/data/resourcedump/resources/res1'))
134
+ expect(resources[0]).not_to receive(:zip_package)
135
+ expect(resources[1]).not_to receive(:zip_package)
136
+ expect(resources[2]).to receive(:zip_package).and_return(zip_package)
54
137
 
55
- stream2 = bitstreams[1]
56
- expect(stream2.content).to eq(File.read('spec/data/resourcedump/resources/res2'))
138
+ expect(zip_packages[2]).to be(zip_package)
139
+ end
140
+
141
+ it 'flatmaps' do
142
+ resources = Array.new(6) { |i| Resource.new(uri: "http://example.org/res#{i}") }
143
+ all_packages = Array.new(6) do |i|
144
+ zip_package = instance_double(Client::Zip::ZipPackage)
145
+ expect(resources[i]).to receive(:zip_package).once.and_return(zip_package)
146
+ zip_package
147
+ end
148
+
149
+ zrl1 = ChangeDump.new(resources: resources[0, 3])
150
+ zrl2 = ChangeDump.new(resources: resources[3, 3])
151
+
152
+ lazy_flat_mapped = [zrl1, zrl2].lazy.flat_map(&:zip_packages).to_a
153
+ expect(lazy_flat_mapped).to eq(all_packages)
154
+
155
+ flat_mapped = [zrl1, zrl2].flat_map(&:zip_packages)
156
+ expect(flat_mapped).to eq(all_packages)
157
+ end
158
+
159
+ it 'supports lazy iteration 'do
160
+ manifests = Array.new(3) { instance_double(ChangeDumpManifest) }
161
+ all_packages = Array.new(3) do |index|
162
+ zip_package = instance_double(Client::Zip::ZipPackage)
163
+ allow(zip_package).to receive(:manifest).and_return(manifests[index])
164
+ zip_package
165
+ end
166
+ resources = Array.new(3) do |index|
167
+ resource = Resource.new(uri: "http://example.org/res#{index}")
168
+ if index > 1
169
+ expect(resource).not_to receive(:zip_package)
170
+ else
171
+ expect(resource).to receive(:zip_package).and_return(all_packages[index])
172
+ end
173
+ resource
57
174
  end
175
+
176
+ zip_packages = ChangeDump.new(resources: resources).zip_packages
177
+ zip_packages.each_with_index do |zip_package, index|
178
+ expect(zip_package.manifest).to be(manifests[index])
179
+ break if index >= 1
180
+ end
181
+ end
182
+ end
183
+
184
+ describe '#all_zip_packages' do
185
+ it 'is an alias for #zip_packages' do
186
+ path = 'spec/data/resourcedump/changedump.xml'
187
+ package_uri = URI('http://example.com/changedump.zip')
188
+
189
+ client = instance_double(Client)
190
+ expect(client).to receive(:download_to_temp_file).once.with(package_uri).and_return('spec/data/resourcedump/resourcedump.zip')
191
+
192
+ dump = XMLParser.parse(File.read(path))
193
+ dump.client = client
194
+
195
+ zip_packages = dump.all_zip_packages
196
+ expect(zip_packages.size).to eq(1)
197
+ expect(zip_packages[0]).to be_a(Client::Zip::ZipPackage)
198
+
199
+ bitstreams = zip_packages[0].bitstreams
200
+ expect(bitstreams.size).to eq(2)
201
+ expect(bitstreams[0].content).to eq(File.read('spec/data/resourcedump/resources/res1'))
202
+ expect(bitstreams[1].content).to eq(File.read('spec/data/resourcedump/resources/res2'))
58
203
  end
59
204
  end
60
205
  end
@@ -41,6 +41,51 @@ module Resync
41
41
  end
42
42
  end
43
43
 
44
+ describe ResourceList do
45
+ describe '#all_resources' do
46
+ it 'is an alias for #resources' do
47
+ resources = Array.new(3) do
48
+ resource = instance_double(Resource)
49
+ allow(resource).to receive(:client_delegate=)
50
+ resource
51
+ end
52
+ list = ResourceList.new(resources: resources)
53
+ expect(list.all_resources).to be(list.resources)
54
+ end
55
+ end
56
+ end
57
+
58
+ describe ChangeList do
59
+ describe '#all_changes' do
60
+ describe '#all_resources' do
61
+ it 'is an alias for #resources' do
62
+ resources = []
63
+ resources[0] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(1999, 1, 1))
64
+ resources[1] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(2000, 1, 1))
65
+ resources[2] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(2001, 3, 1))
66
+
67
+ all_resources = ResourceList.new(resources: resources).all_resources
68
+ expect(all_resources.to_a).to eq(resources)
69
+ end
70
+ end
71
+
72
+ it 'is a proxy for #changes' do
73
+ resources = []
74
+ resources[0] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(1999, 1, 1), metadata: Metadata.new(change: Types::Change::CREATED))
75
+ resources[1] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(2000, 1, 1), metadata: Metadata.new(change: Types::Change::CREATED))
76
+ resources[2] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(1999, 3, 1), metadata: Metadata.new(change: Types::Change::UPDATED))
77
+ resources[3] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(1999, 6, 1), metadata: Metadata.new(change: Types::Change::UPDATED))
78
+ resources[4] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(2000, 3, 1), metadata: Metadata.new(change: Types::Change::UPDATED))
79
+ resources[5] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(2000, 6, 1), metadata: Metadata.new(change: Types::Change::UPDATED))
80
+ resources[6] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(1999, 9, 1), metadata: Metadata.new(change: Types::Change::DELETED))
81
+ resources[7] = Resource.new(uri: 'http://example.org/', modified_time: Time.utc(2000, 9, 1), metadata: Metadata.new(change: Types::Change::DELETED))
82
+ list = ChangeList.new(resources: resources)
83
+ all_changes = list.all_changes(of_type: Types::Change::UPDATED, in_range: Time.utc(1999, 4, 1)..Time.utc(2000, 4, 1))
84
+ expect(all_changes.to_a).to eq([resources[3], resources[4]])
85
+ end
86
+ end
87
+ end
88
+
44
89
  describe BaseChangeIndex do
45
90
  before(:each) do
46
91
  @helper = instance_double(Client::HTTPHelper)
metadata CHANGED
@@ -1,15 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resync-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Moles
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-11 00:00:00.000000000 Z
11
+ date: 2015-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lazy
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.9.6
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.9'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.9.6
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: resync
15
35
  requirement: !ruby/object:Gem::Requirement
@@ -19,7 +39,7 @@ dependencies:
19
39
  version: '0.2'
20
40
  - - ">="
21
41
  - !ruby/object:Gem::Version
22
- version: 0.2.2
42
+ version: 0.3.0
23
43
  type: :runtime
24
44
  prerelease: false
25
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +49,7 @@ dependencies:
29
49
  version: '0.2'
30
50
  - - ">="
31
51
  - !ruby/object:Gem::Version
32
- version: 0.2.2
52
+ version: 0.3.0
33
53
  - !ruby/object:Gem::Dependency
34
54
  name: rubyzip
35
55
  requirement: !ruby/object:Gem::Requirement
@@ -142,6 +162,20 @@ dependencies:
142
162
  - - "~>"
143
163
  - !ruby/object:Gem::Version
144
164
  version: '0.8'
165
+ - !ruby/object:Gem::Dependency
166
+ name: codeclimate-test-reporter
167
+ requirement: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - "~>"
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ type: :development
173
+ prerelease: false
174
+ version_requirements: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - "~>"
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
145
179
  description: A Ruby client for the ResourceSync web synchronization framework
146
180
  email:
147
181
  - david.moles@ucop.edu
@@ -177,7 +211,6 @@ files:
177
211
  - lib/resync/client/zip.rb
178
212
  - lib/resync/client/zip/bitstream.rb
179
213
  - lib/resync/client/zip/zip_package.rb
180
- - lib/resync/client/zip/zip_packages.rb
181
214
  - resync-client.gemspec
182
215
  - spec/acceptance/example_spec.rb
183
216
  - spec/data/examples/capability-list.xml
@@ -210,6 +243,8 @@ files:
210
243
  - spec/spec_helper.rb
211
244
  - spec/todo.rb
212
245
  - spec/unit/resync/client/bitstream_spec.rb
246
+ - spec/unit/resync/client/change_dump_index_spec.rb
247
+ - spec/unit/resync/client/change_dump_spec.rb
213
248
  - spec/unit/resync/client/client_spec.rb
214
249
  - spec/unit/resync/client/dump_index_spec.rb
215
250
  - spec/unit/resync/client/dump_spec.rb
@@ -217,7 +252,6 @@ files:
217
252
  - spec/unit/resync/client/http_helper_spec.rb
218
253
  - spec/unit/resync/client/list_index_spec.rb
219
254
  - spec/unit/resync/client/zip_package_spec.rb
220
- - spec/unit/resync/client/zip_packages_spec.rb
221
255
  homepage: http://github.com/dmolesUC3/resync-client
222
256
  licenses:
223
257
  - MIT
@@ -238,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
238
272
  version: '0'
239
273
  requirements: []
240
274
  rubyforge_project:
241
- rubygems_version: 2.4.7
275
+ rubygems_version: 2.4.6
242
276
  signing_key:
243
277
  specification_version: 4
244
278
  summary: Client library for ResourceSync
@@ -274,6 +308,8 @@ test_files:
274
308
  - spec/spec_helper.rb
275
309
  - spec/todo.rb
276
310
  - spec/unit/resync/client/bitstream_spec.rb
311
+ - spec/unit/resync/client/change_dump_index_spec.rb
312
+ - spec/unit/resync/client/change_dump_spec.rb
277
313
  - spec/unit/resync/client/client_spec.rb
278
314
  - spec/unit/resync/client/dump_index_spec.rb
279
315
  - spec/unit/resync/client/dump_spec.rb
@@ -281,5 +317,4 @@ test_files:
281
317
  - spec/unit/resync/client/http_helper_spec.rb
282
318
  - spec/unit/resync/client/list_index_spec.rb
283
319
  - spec/unit/resync/client/zip_package_spec.rb
284
- - spec/unit/resync/client/zip_packages_spec.rb
285
320
  has_rdoc:
@@ -1,69 +0,0 @@
1
- require 'resync'
2
- require_relative '../mixins'
3
- require_relative 'zip_package'
4
-
5
- module Resync
6
- class Client
7
- module Zip
8
- # Lazily retrieves and caches the zip packages for the specified
9
- # list of resources. The packages are cached to temporary files
10
- # which are deleted on exit; if they are deleted while the
11
- # interpreter is running, the behavior is undefined (but bad things
12
- # are likely to happen).
13
- class ZipPackages
14
- include Enumerable
15
-
16
- # Creates a new {ZipPackages} wrapper for the specified list
17
- # of resources.
18
- # @param resources [Array<Resource>] The list of resources to
19
- # get zip packages for.
20
- def initialize(resources)
21
- @resources = resources
22
- @packages = {}
23
- end
24
-
25
- # Gets the size of this list of packages.
26
- # @return the size of the underlying array.
27
- def size
28
- @resources.size
29
- end
30
-
31
- # Gets the zip package at the specified index, downloading it
32
- # if necessary.
33
- #
34
- # @return [ZipPackage] the zip package for the resource at the
35
- # specified index in the underlying array.
36
- def [](key)
37
- resource = @resources[key]
38
- package_for(resource)
39
- end
40
-
41
- # Gets the zip package for the specified resource, downloading it
42
- # if necessary.
43
- # @return [ZipPackage] the package for the resource
44
- def package_for(resource)
45
- @packages[resource] ||= resource.zip_package
46
- end
47
-
48
- # Lazily iterates the given block for each zip package, downloading
49
- # as necessary.
50
- # @yield [ZipPackage] the zip package for each resource
51
- def each
52
- @resources.lazy.each do |resource|
53
- yield package_for(resource)
54
- end
55
- end
56
-
57
- # Eagerly gets the zip package for each resource, downloading
58
- # as necessary. (For compatbility with {::Enumerator::Lazy#flat_map})
59
- # @return [Array<ZipPackage>] the zip package for each resource
60
- def force
61
- @resources.map { |r| package_for(r) }.to_a
62
- end
63
-
64
- # Alias for {#force} (for compatbility with {::Enumerable#flat_map})
65
- alias_method :to_ary, :force
66
- end
67
- end
68
- end
69
- end
@@ -1,82 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Resync
4
- class Client
5
- module Zip
6
- describe ZipPackages do
7
- it 'is lazy' do
8
- resources = Array.new(3) { |i| Resource.new(uri: "http://example.org/res#{i}") }
9
-
10
- zip_packages = ZipPackages.new(resources)
11
-
12
- zip_package = instance_double(ZipPackage)
13
- expect(resources[0]).not_to receive(:zip_package)
14
- expect(resources[1]).not_to receive(:zip_package)
15
- expect(resources[2]).to receive(:zip_package).and_return(zip_package)
16
-
17
- expect(zip_packages[2]).to be(zip_package)
18
- end
19
-
20
- it 'caches zip packages' do
21
- resources = Array.new(3) { |i| Resource.new(uri: "http://example.org/res#{i}") }
22
-
23
- zip_packages = ZipPackages.new(resources)
24
-
25
- zip_package = instance_double(ZipPackage)
26
- expect(resources[1]).to receive(:zip_package).once.and_return(zip_package)
27
-
28
- expect(zip_packages[1]).to be(zip_package)
29
- expect(zip_packages[1]).to be(zip_package)
30
- end
31
-
32
- it 'flatmaps' do
33
- resources = Array.new(6) { |i| Resource.new(uri: "http://example.org/res#{i}") }
34
- all_packages = Array.new(6) do |i|
35
- zip_package = instance_double(ZipPackage)
36
- expect(resources[i]).to receive(:zip_package).once.and_return(zip_package)
37
- zip_package
38
- end
39
-
40
- zip_packages_1 = ZipPackages.new(resources[0, 3])
41
- zip_packages_2 = ZipPackages.new(resources[3, 3])
42
-
43
- zrl1 = instance_double(Resync::Client::Mixins::Dump)
44
- expect(zrl1).to receive(:zip_packages).twice.and_return(zip_packages_1)
45
-
46
- zrl2 = instance_double(Resync::Client::Mixins::Dump)
47
- expect(zrl2).to receive(:zip_packages).twice.and_return(zip_packages_2)
48
-
49
- flat_mapped = [zrl1, zrl2].flat_map(&:zip_packages)
50
- expect(flat_mapped).to eq(all_packages)
51
-
52
- lazy_flat_mapped = [zrl1, zrl2].lazy.flat_map(&:zip_packages).to_a
53
- expect(lazy_flat_mapped).to eq(all_packages)
54
- end
55
-
56
- it 'supports lazy iteration' do
57
- manifests = Array.new(3) { instance_double(ChangeDumpManifest) }
58
- all_packages = Array.new(3) do |index|
59
- zip_package = instance_double(ZipPackage)
60
- allow(zip_package).to receive(:manifest).and_return(manifests[index])
61
- zip_package
62
- end
63
- resources = Array.new(3) do |index|
64
- resource = Resource.new(uri: "http://example.org/res#{index}")
65
- if index > 1
66
- expect(resource).not_to receive(:zip_package)
67
- else
68
- expect(resource).to receive(:zip_package).and_return(all_packages[index])
69
- end
70
- resource
71
- end
72
-
73
- zip_packages = ZipPackages.new(resources)
74
- zip_packages.each_with_index do |zip_package, index|
75
- expect(zip_package.manifest).to be(manifests[index])
76
- break if index >= 1
77
- end
78
- end
79
- end
80
- end
81
- end
82
- end