resync-client 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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