iiif-presentation 0.0.4

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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE +23 -0
  7. data/README.md +173 -0
  8. data/Rakefile +12 -0
  9. data/VERSION +1 -0
  10. data/gemfiles/rails3.gemfile +5 -0
  11. data/gemfiles/rails4.gemfile +5 -0
  12. data/iiif-presentation.gemspec +28 -0
  13. data/lib/active_support/ordered_hash.rb +147 -0
  14. data/lib/iiif/hash_behaviours.rb +150 -0
  15. data/lib/iiif/presentation.rb +25 -0
  16. data/lib/iiif/presentation/abstract_resource.rb +75 -0
  17. data/lib/iiif/presentation/annotation.rb +25 -0
  18. data/lib/iiif/presentation/annotation_list.rb +28 -0
  19. data/lib/iiif/presentation/canvas.rb +45 -0
  20. data/lib/iiif/presentation/collection.rb +29 -0
  21. data/lib/iiif/presentation/image_resource.rb +115 -0
  22. data/lib/iiif/presentation/layer.rb +34 -0
  23. data/lib/iiif/presentation/manifest.rb +39 -0
  24. data/lib/iiif/presentation/range.rb +32 -0
  25. data/lib/iiif/presentation/resource.rb +21 -0
  26. data/lib/iiif/presentation/sequence.rb +35 -0
  27. data/lib/iiif/service.rb +418 -0
  28. data/spec/fixtures/manifests/complete_from_spec.json +171 -0
  29. data/spec/fixtures/manifests/minimal.json +40 -0
  30. data/spec/fixtures/manifests/service_only.json +11 -0
  31. data/spec/fixtures/vcr_cassettes/pul_loris_cassette.json +159 -0
  32. data/spec/integration/iiif/presentation/image_resource_spec.rb +123 -0
  33. data/spec/integration/iiif/service_spec.rb +211 -0
  34. data/spec/spec_helper.rb +104 -0
  35. data/spec/unit/active_support/ordered_hash_spec.rb +155 -0
  36. data/spec/unit/iiif/hash_behaviours_spec.rb +569 -0
  37. data/spec/unit/iiif/presentation/abstract_resource_spec.rb +133 -0
  38. data/spec/unit/iiif/presentation/annotation_list_spec.rb +7 -0
  39. data/spec/unit/iiif/presentation/annotation_spec.rb +7 -0
  40. data/spec/unit/iiif/presentation/canvas_spec.rb +40 -0
  41. data/spec/unit/iiif/presentation/collection_spec.rb +54 -0
  42. data/spec/unit/iiif/presentation/image_resource_spec.rb +13 -0
  43. data/spec/unit/iiif/presentation/layer_spec.rb +38 -0
  44. data/spec/unit/iiif/presentation/manifest_spec.rb +89 -0
  45. data/spec/unit/iiif/presentation/range_spec.rb +43 -0
  46. data/spec/unit/iiif/presentation/resource_spec.rb +16 -0
  47. data/spec/unit/iiif/presentation/sequence_spec.rb +110 -0
  48. data/spec/unit/iiif/presentation/shared_examples/abstract_resource_only_keys.rb +43 -0
  49. data/spec/unit/iiif/presentation/shared_examples/any_type_keys.rb +33 -0
  50. data/spec/unit/iiif/presentation/shared_examples/array_only_keys.rb +44 -0
  51. data/spec/unit/iiif/presentation/shared_examples/int_only_keys.rb +49 -0
  52. data/spec/unit/iiif/presentation/shared_examples/string_only_keys.rb +29 -0
  53. data/spec/unit/iiif/service_spec.rb +10 -0
  54. metadata +262 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1e600987059a68eef0064df0b7d4a62606af135e
4
+ data.tar.gz: d1a85d821d52a370f9c3b0cd27383437cd242694
5
+ SHA512:
6
+ metadata.gz: 65ab0328b4f5c514e4c6a3860d24aa00d0d9908971d64ff0a36fd000d552c1992711700c30ea690a43b1a436b3c8b459242d1f853a01a71b0b699a4685fd8228
7
+ data.tar.gz: e210d147df7c6ce971c518c5f117c2918aadab3ad9f4e115a3add980453f81251a33acd3ec69dcb576b0f5157c23b14df37f9517e4b82505d8ae9fa09cc32eb0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ coverage/
2
+ pkg/
3
+ Gemfile.lock
4
+
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.1.0
5
+ gemfile:
6
+ - gemfiles/rails3.gemfile
7
+ - gemfiles/rails4.gemfile
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2014, Jon Stroop
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # O'Sullivan: A Ruby API for working with IIIF Presentation manifests
2
+
3
+ [![Build Status](https://travis-ci.org/IIIF/osullivan.svg?branch=development)](https://travis-ci.org/IIIF/osullivan)
4
+ [![Coverage Status](https://coveralls.io/repos/IIIF/osullivan/badge.svg?branch=development&service=github)](https://coveralls.io/github/IIIF/osullivan?branch=development)
5
+
6
+
7
+ ## Installation
8
+
9
+ From the source code do `rake install`, or get the latest release [from RubyGems](https://rubygems.org/gems/iiif-presentation).
10
+
11
+ ## Building New Objects
12
+
13
+ There is (or will be) a class for all types in [IIIF Presentation API Spec](http://iiif.io/api/presentation/2.0/).
14
+
15
+
16
+
17
+
18
+ ```ruby
19
+ require 'iiif/presentation'
20
+
21
+ seed = {
22
+ '@id' => 'http://example.com/manifest',
23
+ 'label' => 'My Manifest'
24
+ }
25
+ # Any options you add are added to the object
26
+ manifest = IIIF::Presentation::Manifest.new(seed)
27
+
28
+ canvas = IIIF::Presentation::Canvas.new()
29
+ # All classes act like `ActiveSupport::OrderedHash`es, for the most part.
30
+ # Use `[]=` to set JSON-LD properties...
31
+ canvas['@id'] = 'http://example.com/canvas'
32
+ # ...but there are also accessors and mutators for the properties mentioned in
33
+ # the spec
34
+ canvas.width = 10
35
+ canvas.height = 20
36
+ canvas.label = 'My Canvas'
37
+
38
+ oc = IIIF::Presentation::Resource.new('@id' => 'http://example.com/content')
39
+ canvas.other_content << oc
40
+
41
+ manifest.sequences << canvas
42
+
43
+ puts manifest.to_json(pretty: true)
44
+ ```
45
+
46
+ Methods are generated dynamically, which means `#methods` is your friend:
47
+
48
+ ```ruby
49
+ manifest = IIIF::Presentation::Manifest.new()
50
+ puts manifest.methods(false)
51
+ > label=
52
+ > label
53
+ > description=
54
+ > description
55
+ > thumbnail=
56
+ > thumbnail
57
+ > attribution=
58
+ > attribution
59
+ > viewing_hint=
60
+ > viewingHint=
61
+ > viewing_hint
62
+ > viewingHint
63
+ [...]
64
+ ```
65
+
66
+ Note that multi-word properties are implemented as snake_case (because this is
67
+ Ruby), but is serialized as camelCase. There are camelCase aliases for these.
68
+
69
+ ```ruby
70
+ manifest = IIIF::Presentation::Manifest.new()
71
+ manifest.viewing_hint = 'paged'
72
+ puts manifest.to_json(pretty: true, force: true) # force: true skips validations
73
+
74
+ > {
75
+ > "@context": "http://iiif.io/api/presentation/2/context.json",
76
+ > "@type": "sc:Manifest",
77
+ > "viewingHint": "paged"
78
+ > }
79
+
80
+ ```
81
+
82
+ ## Parsing Existing Objects
83
+
84
+ Use `IIIF::Service#parse`. It will figure out what the object
85
+ should be, based on `@type`, and fall back to `ActiveSupport::OrderedHash` when
86
+ it can't e.g.:
87
+
88
+ ```ruby
89
+ seed = '{
90
+ "@context": "http://iiif.io/api/presentation/2/context.json",
91
+ "@id": "http://example.com/manifest",
92
+ "@type": "sc:Manifest",
93
+ "label": "My Manifest",
94
+ "service": {
95
+ "@context": "http://iiif.io/api/image/2/context.json",
96
+ "@id":"http://www.example.org/images/book1-page1",
97
+ "profile":"http://iiif.io/api/image/2/profiles/level2.json"
98
+ },
99
+ "seeAlso": {
100
+ "@id": "http://www.example.org/library/catalog/book1.marc",
101
+ "format": "application/marc"
102
+ },
103
+ "sequences": [
104
+ {
105
+ "@id":"http://www.example.org/iiif/book1/sequence/normal",
106
+ "@type":"sc:Sequence",
107
+ "label":"Current Page Order",
108
+ "viewingDirection":"left-to-right",
109
+ "viewingHint":"paged",
110
+ "startCanvas": "http://www.example.org/iiif/book1/canvas/p2",
111
+ "canvases": [
112
+ {
113
+ "@id": "http://example.com/canvas",
114
+ "@type": "sc:Canvas",
115
+ "width": 10,
116
+ "height": 20,
117
+ "label": "My Canvas",
118
+ "otherContent": [
119
+ {
120
+ "@id": "http://example.com/content",
121
+ "@type":"sc:AnnotationList",
122
+ "motivation": "sc:painting"
123
+ }
124
+ ]
125
+ }
126
+ ]
127
+ }
128
+ ]
129
+ }'
130
+
131
+ obj = IIIF::Service.parse(seed) # can also be a file path or a Hash
132
+ puts obj.class
133
+ puts obj.see_also.class
134
+
135
+ > IIIF::Presentation::Manifest
136
+ > ActiveSupport::OrderedHash
137
+ ```
138
+
139
+ ## Validation and Exceptions
140
+
141
+ This is work in progress. Right now exceptions are generally raised when you
142
+ try to set something to a type it should never be:
143
+
144
+ ```ruby
145
+ manifest = IIIF::Presentation::Manifest.new
146
+ manifest.sequences = 'quux'
147
+
148
+ > [...] sequences must be an Array. (IIIF::Presentation::IllegalValueError)
149
+ ```
150
+
151
+ and also if any required properties are missing when calling `to_json`
152
+
153
+ ```ruby
154
+ canvas = IIIF::Presentation::Canvas.new('@id' => 'http://example.com/canvas')
155
+ puts canvas.to_json(pretty: true)
156
+
157
+ > A(n) width is required for each IIIF::Presentation::Canvas (IIIF::Presentation::MissingRequiredKeyError)
158
+ ```
159
+
160
+ but you can skip this validation by adding `force: true`:
161
+
162
+ ```ruby
163
+ canvas = IIIF::Presentation::Canvas.new('@id' => 'http://example.com/canvas')
164
+ puts canvas.to_json(pretty: true, force: true)
165
+
166
+ > {
167
+ > "@context": "http://iiif.io/api/presentation/2/context.json",
168
+ > "@id": "http://example.com/canvas",
169
+ > "@type": "sc:Canvas"
170
+ > }
171
+ ```
172
+ This all needs a bit of tidying up, finishing, and refactoring, so expect it to
173
+ change.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :ci do
9
+ Rake::Task['spec'].invoke
10
+ end
11
+
12
+ task default: :ci
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.4
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec :path=>"../"
4
+
5
+ gem 'activesupport', '~> 3.2', '>= 3.2.18'
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec :path=>"../"
4
+
5
+ gem 'activesupport', '~> 4.1'
@@ -0,0 +1,28 @@
1
+ version = File.read(File.expand_path('../VERSION', __FILE__)).strip
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'iiif-presentation'
5
+ spec.version = version
6
+ spec.authors = ['Jon Stroop']
7
+ spec.email = ['jpstroop@gmail.com']
8
+ spec.description = 'API for working with IIIF Presentation manifests.'
9
+ spec.summary = 'API for working with IIIF Presentation manifests.'
10
+ spec.license = 'Simplified BSD'
11
+ spec.homepage = 'https://github.com/iiif/osullivan'
12
+
13
+ spec.files = `git ls-files`.split($/)
14
+ spec.test_files = spec.files.grep(%r{^spec/})
15
+ spec.require_paths = ['lib']
16
+
17
+ spec.add_development_dependency 'bundler'
18
+ spec.add_development_dependency 'rake'
19
+ spec.add_development_dependency 'rspec'
20
+ spec.add_development_dependency 'coveralls'
21
+ spec.add_development_dependency 'webmock'
22
+ spec.add_development_dependency 'multi_json'
23
+ spec.add_development_dependency 'vcr', '~> 2.9.3'
24
+
25
+ spec.add_dependency 'json'
26
+ spec.add_dependency 'activesupport', '>= 3.2.18'
27
+ spec.add_dependency 'faraday', '~> 0.9.0'
28
+ end
@@ -0,0 +1,147 @@
1
+ require 'active_support/inflector'
2
+ require 'active_support/ordered_hash'
3
+
4
+ module ActiveSupport
5
+ class OrderedHash < ::Hash
6
+
7
+ # Insert a new key and value at the suppplied index.
8
+ #
9
+ # Note that this is slightly different from Array#insert in that new
10
+ # entries must be added one at a time, i.e. insert(n, k, v, k, v...) is
11
+ # not supported.
12
+ #
13
+ # @param [Integer] index
14
+ # @param [Object] key
15
+ # @param [Object] value
16
+ def insert(index, key, value)
17
+ tmp = ActiveSupport::OrderedHash.new
18
+ index = self.length + 1 + index if index < 0
19
+ if index < 0
20
+ m = "Index #{index} is too small for current length (#{length})"
21
+ raise IndexError, m
22
+ end
23
+ if index > 0
24
+ i=0
25
+ self.each do |k,v|
26
+ tmp[k] = v
27
+ self.delete(k)
28
+ i+=1
29
+ break if i == index
30
+ end
31
+ end
32
+ tmp[key] = value
33
+ tmp.merge!(self) # copy the remaining to tmp
34
+ self.clear # start over...
35
+ self.merge!(tmp) # now put them all back
36
+ self
37
+ end
38
+
39
+ # Insert a key and value before an existing key or the first entry for'
40
+ # which the supplied block evaluates to true. The block takes precendence
41
+ # over the supplied key.
42
+ # Options:'
43
+ # * :existing_key (default: nil). If nil or not supplied then a block is required.
44
+ # * :new_key (required)
45
+ # * :value (required)
46
+ # @raise KeyError if the supplied existing key is not found, the new
47
+ # key exists, or the block never evaluates to true.
48
+ def insert_before(hsh, &block)
49
+ existing_key = hsh.fetch(:existing_key, nil)
50
+ new_key = hsh[:new_key]
51
+ value = hsh[:value]
52
+ if block_given?
53
+ self.insert_here(0, new_key, value, &block)
54
+ else
55
+ self.insert_here(0, new_key, value, existing_key)
56
+ end
57
+ end
58
+
59
+ # Insert a key and value after an existing key or the first entry for'
60
+ # which the supplied block evaluates to true. The block takes precendence
61
+ # over the supplied key.
62
+ # Options:'
63
+ # * :existing_key (default: nil). If nil or not supplied then a block is required.
64
+ # * :new_key (required)
65
+ # * :value (required)
66
+ # @raise KeyError if the supplied existing key is not found, the new
67
+ # key exists, or the block never evaluates to true.
68
+ def insert_after(hsh, &block)
69
+ existing_key = hsh.fetch(:existing_key, nil)
70
+ new_key = hsh[:new_key]
71
+ value = hsh[:value]
72
+ if block_given?
73
+ self.insert_here(1, new_key, value, &block)
74
+ else
75
+ self.insert_here(1, new_key, value, existing_key)
76
+ end
77
+ end
78
+
79
+ # Delete any keys that are empty arrays
80
+ def remove_empties
81
+ self.keys.each do |key|
82
+ if (self[key].kind_of?(Array) && self[key].empty?) || self[key].nil?
83
+ self.delete(key)
84
+ end
85
+ end
86
+ end
87
+
88
+ # Covert snake_case keys to camelCase
89
+ def camelize_keys
90
+ self.keys.each_with_index do |key, i|
91
+ if key != key.camelize(:lower)
92
+ self.insert(i, key.camelize(:lower), self[key])
93
+ self.delete(key)
94
+ end
95
+ end
96
+ self
97
+ end
98
+
99
+ # Covert camelCase keys to snake_case
100
+ def snakeize_keys
101
+ self.keys.each_with_index do |key, i|
102
+ if key != key.underscore
103
+ self.insert(i, key.underscore, self[key])
104
+ self.delete(key)
105
+ end
106
+ end
107
+ self
108
+ end
109
+
110
+
111
+ # Prepends an entry to the front of the object.
112
+ # Note that this is slightly different from Array#unshift in that new
113
+ # entries must be added one at a time, i.e. unshift([k,v],[k,v],...) is
114
+ # not currently supported.
115
+ def unshift k,v
116
+ self.insert(0, k, v)
117
+ self
118
+ end
119
+
120
+ protected
121
+ def insert_here(where, new_key, value, existing_key=nil, &block)
122
+ idx = nil
123
+ if block_given?
124
+ self.each_with_index do |(k,v), i|
125
+ if yield(k, v)
126
+ idx = i
127
+ break
128
+ end
129
+ end
130
+ if idx.nil?
131
+ raise KeyError, "Supplied block never evaluates to true"
132
+ end
133
+ else
134
+ unless self.has_key?(existing_key)
135
+ raise KeyError, "Existing key '#{existing_key}' does not exist"
136
+ end
137
+ if self.has_key?(new_key)
138
+ raise KeyError, "Supplied new key '#{new_key}' already exists"
139
+ end
140
+ idx = self.keys.index(existing_key) + where
141
+ end
142
+ self.insert(idx, new_key, value)
143
+ self
144
+ end
145
+
146
+ end
147
+ end
@@ -0,0 +1,150 @@
1
+ require 'forwardable'
2
+
3
+ module IIIF
4
+ module HashBehaviours
5
+ extend Forwardable
6
+
7
+ # TODO:
8
+ # * reject
9
+ # * replace
10
+
11
+ def_delegators :@data, :[], :[]=, :camelize_keys, :delete, :empty?,
12
+ :fetch, :has_key?, :has_value?, :include?, :insert, :insert_after,
13
+ :insert_before, :key, :key?, :keys, :length, :member?, :shift, :size,
14
+ :snakeize_keys, :store, :unshift, :value?, :values
15
+
16
+
17
+ ###
18
+ # Methods that take a block and should return an instance (self or a new'
19
+ # instance) have been overridden to do so, rather than an'
20
+ # ActiveSupport::OrderedHash based on the internal hash
21
+
22
+ SIMPLE_SELF_RETURNERS = %w[delete_if each each_key each_value keep_if]
23
+
24
+ SIMPLE_SELF_RETURNERS.each do |method_name|
25
+ define_method(method_name) do |*arg, &block|
26
+ unless block.nil? # block_given? doesn't seem to work in this context
27
+ @data.send(method_name, *arg, &block)
28
+ return self
29
+ else
30
+ @data.send(method_name)
31
+ end
32
+ end
33
+ end
34
+
35
+ # Clear is the only method that returns self but doesn't accept a block
36
+ def clear
37
+ @data.clear
38
+ return self
39
+ end
40
+
41
+ # Returns a new instance of this class containing the contents of'
42
+ # another_obj. The argument can be any object that implements two
43
+ # methods:
44
+ #
45
+ # obj.each { |k,v| block }
46
+ # obj.has_key?
47
+ #
48
+ # If no block is specified, the value for entries with duplicate keys'
49
+ # will be those of the argument, but at the index of the original; all'
50
+ # other entries will be appended to the end.
51
+ #
52
+ # If a block is specified the value for each duplicate key is determined'
53
+ # by calling the block with the key, its value in hsh and its value in'
54
+ # another_obj.
55
+ def merge another_obj
56
+ new_instance = self.class.new
57
+ # self.clone # Would this be better? What happens to other attributes of the class?
58
+ if block_given?
59
+ self.each do |k,v|
60
+ if another_obj.has_key? k
61
+ new_instance[k] = yield(k, self[k], another_obj[k])
62
+ else
63
+ new_instance[k] = v
64
+ end
65
+ end
66
+ else
67
+ self.each { |k,v| new_instance[k] = v }
68
+ another_obj.each { |k,v| new_instance[k] = v }
69
+ end
70
+ new_instance
71
+ end
72
+
73
+ # Adds the entries from another obj to this one. The argument can be any
74
+ # object that implements two methods:
75
+ #
76
+ # obj.each { |k,v| block }
77
+ # obj.has_key?
78
+ #
79
+ # If no block is specified, the value for entries with duplicate keys'
80
+ # will be those of the argument, but at the index of the original; all'
81
+ # other entries will be appended to the end.
82
+ #
83
+ # If a block is specified the value for each duplicate key is determined'
84
+ # by calling the block with the key, its value in hsh and its value in'
85
+ # another_obj.
86
+ def merge! another_obj
87
+ if block_given?
88
+ self.each do |k,v|
89
+ if another_obj.has_key? k
90
+ self[k] = yield(k, self[k], another_obj[k])
91
+ else
92
+ self[k] = v
93
+ end
94
+ end
95
+ else
96
+ self.each { |k,v| self[k] = v }
97
+ another_obj.each { |k,v| self[k] = v }
98
+ end
99
+ self
100
+ end
101
+ alias update merge!
102
+
103
+ # Deletes entries for which the supplied block evaluates to true.
104
+ # Equivalent to #delete_if, but returns nil if there were no changes
105
+ def reject!
106
+ if block_given?
107
+ return_nil = true
108
+ @data.each do |k, v|
109
+ if yield(k, v)
110
+ @data.delete(k)
111
+ return_nil = false
112
+ end
113
+ end
114
+ return return_nil ? nil : self
115
+ else
116
+ return self.data.reject!
117
+ end
118
+ end
119
+
120
+ # Returns a new instance consisting of entries for which the block returns
121
+ # true. Not that an enumerator is not available for the OrderedHash'
122
+ # implementation
123
+ def select
124
+ new_instance = self.class.new
125
+ if block_given?
126
+ @data.each { |k,v| new_instance.data[k] = v if yield(k,v) }
127
+ end
128
+ return new_instance
129
+ end
130
+
131
+ # Deletes entries for which the supplied block evaluates to false.
132
+ # Equivalent to Hash#keep_if, but returns nil if no changes were made.
133
+ def select!
134
+ if block_given?
135
+ return_nil = true
136
+ @data.each do |k,v|
137
+ unless yield(k,v)
138
+ @data.delete(k)
139
+ return_nil = false
140
+ end
141
+ end
142
+ return nil if return_nil
143
+ end
144
+ self
145
+ end
146
+
147
+ end
148
+
149
+ end
150
+