reactive_extensions 0.4.0.beta2 → 0.5.0.beta

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: a11a55078afe921816c40afd0f23d18393aaa427
4
- data.tar.gz: aad0e58be3dfce1485fa97d16b866bd6b824590a
3
+ metadata.gz: f7bca1cd49086c183e79ac85eaf3a58a6adc0108
4
+ data.tar.gz: 515ab851d82683790e91dd98ca40d6ad485f6030
5
5
  SHA512:
6
- metadata.gz: 5c8995508e2190fe170db68c6237861e84cfa802dc3ce90a05298f7022e054a6c31082b04e99f20f442248b14f6aa6e3ad272ce6e07f9929b2d3ecd2e9c55db0
7
- data.tar.gz: 798588d3e82ff3aebdec060b5feefe452271d55e7ada29be6ced89357673f3669d04f9dae459b2e3828f90df89c64cb584609679eaaa9f6ce32cf0e42a3a3bdb
6
+ metadata.gz: 1f11b8b5d55f1e4fa906377f1a5a971478a065030d41833078b67b14483bf697668904a2030ef4cc0ed1f54be9fb09a30011088021923c45197cdeb48d052932
7
+ data.tar.gz: 4c35089ef2785298090e0cbd6991163eaf9ca80e4264e8f6a15c80e9019cec0a7154715dea75784500e449f04f5d3bdb9bd50be11e1d84f7bb5999c0283c1411
data/README.md CHANGED
@@ -6,14 +6,14 @@ in the spirit of [ActiveSupport](https://github.com/rails/activesupport). This g
6
6
  be used in any kind of project and is not dependent on any frameworks, gemsets, etc.
7
7
  Its only runtime dependency is [ReactiveSupport](https://github.com/danascheider/reactive_support).
8
8
  To add ReactiveExtensions to your project, add this to your Gemfile and run `bundle install`:
9
- <pre><code>gem 'reactive_extensions', '~> 0.4.0.beta'</code></pre>
9
+ <pre><code>gem 'reactive_extensions', '~> 0.5.0.beta'</code></pre>
10
10
  To install locally:
11
11
  <pre><code>sudo gem install reactive_extensions</code></pre>
12
12
  Or if you're using RVM:
13
13
  <pre><code>gem install reactive_extensions</code></pre>
14
14
 
15
15
  You can also point your Gemfile to this repo:
16
- <pre><code>gem 'reactive_extensions', '~> 0.4.0.beta', git: 'https://github.com/danascheider/reactive_extensions.git</code></pre>
16
+ <pre><code>gem 'reactive_extensions', '~> 0.5.0.beta', git: 'https://github.com/danascheider/reactive_extensions.git</code></pre>
17
17
 
18
18
  After installing, simply include this in your main project file:
19
19
  <pre><code>require 'reactive_support'</code></pre>
@@ -0,0 +1,170 @@
1
+ # This file adds the +#clean+, +#clean!+, +#only+, +#only!+, +#standardize+,
2
+ # and +#standardize!+ methods to Ruby's core Hash class. These methods enable
3
+ # the user to easily add or remove particular keys from a hash.
4
+
5
+ # Ruby's core Has class. See documentation for version
6
+ # 2.1.5[http://ruby-doc.org/core-2.1.5/Hash.html],
7
+ # 2.0.0[http://ruby-doc.org/core-2.0.0/Hash.html], or
8
+ # 1.9.3[http://ruby-doc.org/core-1.9.3/Hash.html].
9
+
10
+ class Hash
11
+
12
+ # The +#clean+ method returns a duplicate of the calling hash with the
13
+ # specified +*bad_keys+, if present, removed. If none of the bad keys
14
+ # are present, +#clean+ will simply return a duplicate hash.
15
+ #
16
+ # +#clean+ is a non-destructive method. The original hash will still be
17
+ # unchanged after it is called.
18
+ #
19
+ # +#clean+ may also be called by the aliases +#not+ and +#except+.
20
+ #
21
+ # Examples:
22
+ # hash = {:foo => 'bar', :bar => 'baz'}
23
+ # hash.clean(:foo) # => {:bar => 'baz'}
24
+ # hash.not(:foo, :bar) # => {}
25
+ # hash.except(:bar, :norf) # => {:foo => 'bar'}
26
+ # hash.clean(:norf) # => {:foo => 'bar', :bar => 'baz'}
27
+ # hash # => {:foo => bar', :bar => 'baz'}
28
+
29
+ def clean(*bad_keys)
30
+ dup = self.reject {|key, value| bad_keys.flatten.include?(key) }
31
+ dup
32
+ end
33
+
34
+ alias_method :not, :clean
35
+ alias_method :except, :clean
36
+
37
+ # The +#clean!+ method returns a duplicate of the calling hash with the
38
+ # specified +*bad_keys+, if present, removed. If none of the bad keys
39
+ # are present, +#clean!+ will simply return a duplicate hash.
40
+ #
41
+ # +#clean!+ is a non-destructive method. The original hash will still be
42
+ # unchanged after it is called.
43
+ #
44
+ # +#clean!+ may also be called by the aliases +#not!+ and +#except!+.
45
+ #
46
+ # Examples:
47
+ # hash = {:foo => 'bar', :bar => 'baz'}
48
+ # hash.clean!(:foo) # => {:bar => 'baz'}
49
+ # hash # => {:bar => 'baz'}
50
+ #
51
+ # hash.not!(:foo, :bar) # => {}
52
+ # hash # => {}
53
+ #
54
+ # hash = {:foo => 'bar', :bar => 'baz'}
55
+ # hash.except!(:bar, :norf) # => {:foo => 'bar'}
56
+ # hash # => {:foo => 'bar'}
57
+
58
+ def clean!(*bad_keys)
59
+ reject! {|key, value| bad_keys.flatten.include?(key) }
60
+ self
61
+ end
62
+
63
+ alias_method :not!, :clean!
64
+ alias_method :except!, :clean!
65
+
66
+ # The +#only+ method returns a duplicate of the calling hash with only the
67
+ # specified +*good_keys+, if present. If none of the good keys
68
+ # are present, +#only+ will simply return an empty hash.
69
+ #
70
+ # +#only+ is a non-destructive method. The original hash will still be
71
+ # unchanged after it is called.
72
+ #
73
+ # Examples:
74
+ # hash = {:foo => 'bar', :bar => 'baz'}
75
+ # hash.only(:foo) # => {:foo => 'bar'}
76
+ # hash.only(:qux) # => {}
77
+ # hash # => {:foo => 'bar', :bar => 'baz'}
78
+
79
+ def only(*good_keys)
80
+ dup = self.select {|key, value| good_keys.flatten.include?(key) }
81
+ end
82
+
83
+ # The +#only!+ method returns a duplicate of the calling hash with only the
84
+ # specified +*good_keys+, if present. If none of the good keys
85
+ # are present, +#only!+ will simply return an empty hash.
86
+ #
87
+ # +#only!+ is a destructive method. The original hash will be changed in place
88
+ # when it is called.
89
+ #
90
+ # Examples:
91
+ # hash = {:foo => 'bar', :bar => 'baz'}
92
+ # hash.only!(:foo) # => {:foo => 'bar'}
93
+ # hash.only!(:qux) # => {}
94
+ # hash # => {}
95
+
96
+ def only!(*good_keys)
97
+ select! {|key, value| good_keys.flatten.include?(key) }
98
+ self
99
+ end
100
+
101
+ # The +#standardize+ method returns a duplicate of the calling hash with
102
+ # the +*keys+ specified as arguments. Any other keys in the hash will be
103
+ # removed. Behavior when adding keys depends on whether the +:errors+
104
+ # option is set to +true+ or +false+ (default).
105
+ #
106
+ # If the +:errors+ option is set to +false+, the method will add any missing
107
+ # keys to the hash, populating them with +nil+ values. If +:errors+ is set to
108
+ # +true+, then an +ArgumentError+ will be raised unless all values are
109
+ # present in the hash already.
110
+ #
111
+ # Examples with +:errors => false+:
112
+ # hash = {:foo => 'bar', :bar => 'baz'}
113
+ # hash.standardize(:foo) # => {:foo => 'bar'}
114
+ # hash.standardize(:foo, :qux) # => {:foo => 'bar', :qux => nil}
115
+ # hash # => {:foo => 'bar', :bar => 'baz'}
116
+ #
117
+ # Examples with +:errors => true+:
118
+ # hash = {:foo => 'bar', :bar 'baz'}
119
+ # hash.standardize(:foo, :errors => true) # => {:foo => 'bar'}
120
+ # hash.standardize(:foo, :qux, :errors => true) # => ArgumentError
121
+
122
+ def standardize(*kees)
123
+ options = kees.extract_options!
124
+ dup = deep_dup.only(kees)
125
+
126
+ kees.each do |key|
127
+ unless dup.has_key? key
128
+ raise ArgumentError.new("#{self} is missing required key #{key}") if options[:errors]
129
+ dup[key] = nil
130
+ end
131
+ end
132
+
133
+ dup
134
+ end
135
+
136
+ # The +#standardize!+ method modifies the calling hash such that its
137
+ # keys match the +*kees+ specified as arguments. Any other keys in the hash
138
+ # will be removed. If passed +:errors => true+, an +ArgumentError+ will be
139
+ # raised in the event keys present in the arguments are not present in the
140
+ # calling hash. Otherwise, any such keys will be added to the hash and
141
+ # populated with nil values.
142
+ #
143
+ # +#standardize!+ is a destructive method; the calling hash will be changed
144
+ # in place when it is called.
145
+ #
146
+ # Examples with +:errors => false+:
147
+ # hash = {:foo => 'bar', :bar => 'baz'}
148
+ # hash.standardize!(:foo, :qux) # => {:foo => 'bar', :qux => nil}
149
+ # hash.standardize!(:foo) # => {:foo => 'bar'}
150
+ # hash # => {:foo => 'bar'}
151
+ #
152
+ # Examples with +:errors => true+:
153
+ # hash = {:foo => 'bar', :bar 'baz'}
154
+ # hash.standardize!(:foo, :errors => true) # => {:foo => 'bar'}
155
+ # hash.standardize!(:foo, :qux, :errors => true) # => ArgumentError
156
+ # hash # => {:foo => 'bar'}
157
+
158
+ def standardize!(*kees)
159
+ options = kees.extract_options!
160
+
161
+ kees.each do |key|
162
+ unless only!(kees).has_key? key
163
+ raise ArgumentError.new("#{self} is missing required key #{key}") if options[:errors]
164
+ self[key] = nil
165
+ end
166
+ end
167
+
168
+ self
169
+ end
170
+ end
@@ -0,0 +1,80 @@
1
+ class Hash
2
+
3
+ # The +#subset_of?+ method checks whether the calling hash is a subset
4
+ # of the given +hash+. It returns true if all key-value pairs in
5
+ # the calling hash are also present in the hash passed as an argument.
6
+ # If the calling hash is empty, the method returns true.
7
+ #
8
+ # Examples:
9
+ # hash = {:foo => 'bar', :bar => 'baz', :baz => 'qux'}
10
+ # {:baz => 'qux'}.subset_of? hash # => true
11
+ # {:bar => 'baz', :norf => 'foo'}.subset_of? hash # => false
12
+ # {:norf => 'foo'}.subset_of? hash # => false
13
+ # {:foo => 'qux'}.subset_of? hash # => false
14
+ # {}.subset_of? hash # => true
15
+ # {:foo => 'bar'}.subset_of? 'foobar' # => ArgumentError
16
+
17
+ def subset_of?(hash)
18
+ raise ArgumentError.new("Argument of #subset_of? must share the class of the calling object") unless hash.instance_of? Hash
19
+ each {|key, value| return false unless hash[key] === value }
20
+ true
21
+ end
22
+
23
+ # The +#superset_of?+ method checks whether the calling hash is a superset
24
+ # of the given +hash+. It returns true if all key-value pairs in
25
+ # the calling hash are also present in the hash passed as an argument.
26
+ # If the argument hash is empty, the method returns true.
27
+ #
28
+ # Examples:
29
+ # hash = {:foo => 'bar', :bar => 'baz', :baz => 'qux'}
30
+ # hash.superset_of? {:baz => 'qux'} # => true
31
+ # hash.superset_of? {:bar => 'baz', :norf => 'foo'} # => false
32
+ # hash.superset_of? {:norf => 'foo'} # => false
33
+ # hash.superset_of? {:foo => 'qux'} # => false
34
+ # hash.superset_of? {} # => true
35
+ # {:foo => 'bar'}.superset_of? 'foobar' # => ArgumentError
36
+
37
+ def superset_of?(hash)
38
+ raise ArgumentError.new("Argument of Hash#superset_of? must be a hash") unless hash.instance_of? Hash
39
+ hash.subset_of? self
40
+ end
41
+ end
42
+
43
+ class Array
44
+
45
+ # The +#subset_of?+ method checks whether the calling array is a subset
46
+ # of the given +array+. It returns true if all objects in the calling
47
+ # array are also present in the hash passed as an argument, regardless
48
+ # of order. If the calling array is empty, the method returns true.
49
+ #
50
+ # Examples:
51
+ # array = [1, 2, 3, 4]
52
+ # [1, 3].subset_of? array # => true
53
+ # [1, 6].subset_of? array # => false
54
+ # [].subset_of? array # => true
55
+ # array.subset_of? 'foobar' # => ArgumentError
56
+
57
+ def subset_of?(array)
58
+ raise ArgumentError.new("Argument of Array#subset_of? must be an array") unless array.instance_of? Array
59
+ each {|i| return false unless array.include? i }
60
+ true
61
+ end
62
+
63
+ # The +#superset_of?+ method checks whether the calling array is a superset
64
+ # of the given +array+. It returns true if all objects in the calling array
65
+ # are also present in the array passed as an argument. If the argument array
66
+ # is empty, the method returns true.
67
+ #
68
+ # Examples:
69
+ # array = [1, 2, 3, 4]
70
+ # array.superset_of? [1, 2] # => true
71
+ # array.superset_of? [1, 2, 3, 4] # => true
72
+ # array.superset_of? [3, 6] # => false
73
+ # array.superset_of? [] # => true
74
+ # array.superset_of? {} # => ArgumentError
75
+
76
+ def superset_of?(array)
77
+ raise ArgumentError.new("Argument of Array#superset_of? must be an array") unless array.instance_of? Array
78
+ array.subset_of? self
79
+ end
80
+ end
@@ -0,0 +1,18 @@
1
+ class Hash
2
+
3
+ # The +#-+ method takes a single hash as an argument. It
4
+ # deletes the key-value pairs of the argument from the calling
5
+ # hash. An ArgumentError is raised if the argument is not a
6
+ # hash or not a subset of the
7
+ #
8
+ # Examples:
9
+ # {:foo => 'bar', :baz => :qux} - {:baz => :qux} # => {:foo => 'bar'}
10
+ # {:foo => 'bar'} - {:norf => :raboo} # => {:foo => 'bar'}
11
+ # {:foo => 'bar'} - {:foo => 'bar'}
12
+ # {:foo => 'bar'} - [1, 2, 3] # => ArgumentError
13
+
14
+ def - (hash)
15
+ raise ArgumentError.new("Hash can only be subtracted from its superset") unless superset_of? hash
16
+ deep_dup.reject {|key, value| hash.has_key? key }
17
+ end
18
+ end
@@ -35,22 +35,28 @@ class Object
35
35
  end
36
36
  end
37
37
 
38
- # The +#try_rescue+ method extends ReactiveSupport's +#try+ method so it rescues
39
- # NoMethodErrors and TypeErrors as well as returning +nil+ when called on a +nil+
40
- # value.
41
- #
42
- # Like the +#try+ method, +#try_rescue+ takes 1 or more arguments. The first argument
43
- # is the method to be called on the calling object, passed as a symbol. The others
44
- # are zero or more arguments that will be passed through to that method, and an
45
- # optional block to be likewise passed through.
46
- #
47
- # When called on NilClass, +#try_rescue+ always returns nil.
48
- #
49
- # Example:
50
- # foo = nil
51
- # foo.try_rescue(:has_key?, :bar) # => nil
38
+ # Ruby's core NilClass. See documentation for version
39
+ # 2.1.5[http://ruby-doc.org/core-2.1.5/NilClass.html],
40
+ # 2.0.0[http://ruby-doc.org/core-2.0.0/NilClass.html], or
41
+ # 1.9.3[http://ruby-doc.org/core-1.9.3/NilClass.html].
52
42
 
53
43
  class NilClass
44
+
45
+ # The +#try_rescue+ method extends ReactiveSupport's +#try+ method so it rescues
46
+ # NoMethodErrors and TypeErrors as well as returning +nil+ when called on a +nil+
47
+ # value.
48
+ #
49
+ # Like the +#try+ method, +#try_rescue+ takes 1 or more arguments. The first argument
50
+ # is the method to be called on the calling object, passed as a symbol. The others
51
+ # are zero or more arguments that will be passed through to that method, and an
52
+ # optional block to be likewise passed through.
53
+ #
54
+ # When called on NilClass, +#try_rescue+ always returns nil.
55
+ #
56
+ # Example:
57
+ # foo = nil
58
+ # foo.try_rescue(:has_key?, :bar) # => nil
59
+
54
60
  def try_rescue(*args, &block)
55
61
  nil
56
62
  end
@@ -2,6 +2,7 @@ require 'reactive_support/core_ext/object/duplicable'
2
2
  require 'reactive_support/core_ext/object/deep_dup'
3
3
  require 'reactive_support/core_ext/object/inclusion'
4
4
  require 'reactive_support/core_ext/object/try'
5
+ require 'reactive_support/core_ext/array/extract_options'
5
6
 
6
7
  Dir['./lib/reactive_extensions/**/*.rb'].each {|f| require f }
7
8
 
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
 
9
9
  s.name = 'reactive_extensions'
10
10
  s.version = ReactiveExtensions.gem_version
11
- s.date = '2014-11-29'
11
+ s.date = '2014-11-30'
12
12
 
13
13
  s.description = 'Handy extensions to core Ruby classes'
14
14
  s.summary = 'ReactiveExtensions, a spinoff of ReactiveSupport, adds a variety of useful methods to core Ruby classes.'
data/spec/array_spec.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'reactive_support/core_ext/hash/keys'
3
+ require 'reactive_support/core_ext/array/extract_options'
3
4
 
4
5
  describe Array do
5
6
  describe 'array scoping' do
@@ -9,7 +10,7 @@ describe Array do
9
10
  let(:camus) { { 'name' => 'Albert Camus', 'nationality' => 'French' } }
10
11
  let(:array) { [sartre, russell, wittgenstein, camus] }
11
12
 
12
- describe 'array #scope method' do
13
+ describe 'scope' do
13
14
  context 'symbol keys' do
14
15
  context 'single value' do
15
16
  it 'returns scoped hashes' do
@@ -41,7 +42,7 @@ describe Array do
41
42
  end
42
43
  end
43
44
 
44
- describe 'array #where_not method' do
45
+ describe 'where_not' do
45
46
  context 'symbol keys' do
46
47
  context 'single value' do
47
48
  it 'returns scoped hashes' do
@@ -73,4 +74,82 @@ describe Array do
73
74
  end
74
75
  end
75
76
  end
77
+
78
+ describe 'sets' do
79
+ describe 'subset_of?' do
80
+ context 'when the argument is a strict superset of the subject' do
81
+ it 'returns true' do
82
+ expect([1, 2].subset_of? [1, 2, 3, 4]).to be true
83
+ end
84
+ end
85
+
86
+ context 'when the argument is equal to the subject' do
87
+ it 'returns true' do
88
+ expect([1, 2].subset_of? [1, 2]).to be true
89
+ end
90
+ end
91
+
92
+ context 'when the calling array is empty' do
93
+ it 'returns true' do
94
+ expect([].subset_of?(['foo', 'bar', 'baz'])).to be true
95
+ end
96
+ end
97
+
98
+ context 'when the elements are not consecutive' do
99
+ it 'returns true' do
100
+ expect([2, 4].subset_of? [1, 2, 3, 4]).to be true
101
+ end
102
+ end
103
+
104
+ context 'when the calling object is inside the argument' do
105
+ it 'returns false' do
106
+ expect([1, 2].subset_of? [[1, 2], 3, 4]).to be false
107
+ end
108
+ end
109
+
110
+ context 'when the argument is not an array' do
111
+ it 'raises an error' do
112
+ expect{[1, 2].subset_of? {}}.to raise_error(ArgumentError)
113
+ end
114
+ end
115
+ end
116
+
117
+ describe 'superset_of?' do
118
+ context 'when the argument is a strict subset of the subject' do
119
+ it 'returns true' do
120
+ expect([1, 2, 3, 4].superset_of? [1, 2]).to be true
121
+ end
122
+ end
123
+
124
+ context 'when the argument is equal to the subject' do
125
+ it 'returns true' do
126
+ expect([1, 2].superset_of? [1, 2]).to be true
127
+ end
128
+ end
129
+
130
+ context 'when the argument array is empty' do
131
+ it 'returns true' do
132
+ expect(['foo', 'bar', 'baz'].superset_of?([])).to be true
133
+ end
134
+ end
135
+
136
+ context 'when the elements are not consecutive' do
137
+ it 'returns true' do
138
+ expect([1, 2, 3, 4].superset_of? [1, 4]).to be true
139
+ end
140
+ end
141
+
142
+ context 'when the argument is a single index' do
143
+ it 'returns false' do
144
+ expect([[1, 2], 3, 4].superset_of? [1, 2]).to be false
145
+ end
146
+ end
147
+
148
+ context 'when the argument is not an array' do
149
+ it 'raises an error' do
150
+ expect{[1, 2].superset_of? 427}.to raise_error(ArgumentError)
151
+ end
152
+ end
153
+ end
154
+ end
76
155
  end
data/spec/hash_spec.rb ADDED
@@ -0,0 +1,321 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hash do
4
+ let(:hash) { { :foo => 'bar', :baz => 'qux' } }
5
+
6
+ describe '-' do
7
+ context 'when the argument is a subset of the calling hash' do
8
+ it 'removes the keys of the argument from the calling hash' do
9
+ expect(hash - {:baz => 'qux'}).to eql({:foo => 'bar'})
10
+ end
11
+ end
12
+
13
+ context 'when the argument has additional keys' do
14
+ it 'raises an argument error' do
15
+ expect{ hash - {:baz => 'qux', :norf => 'raboof'} }.to raise_error(ArgumentError)
16
+ end
17
+ end
18
+
19
+ context 'shared keys with unshared values' do
20
+ it 'raises an error' do
21
+ expect{ hash - {:foo => 'baz'} }.to raise_error(ArgumentError)
22
+ end
23
+ end
24
+
25
+ context 'when the argument is not a hash' do
26
+ it 'raises an ArgumentError' do
27
+ expect{ hash - 'foobar' }.to raise_error(ArgumentError)
28
+ end
29
+ end
30
+ end
31
+
32
+ describe 'clean' do
33
+ it 'removes specified keys' do
34
+ expect(hash.clean(:baz)).to eql({:foo => 'bar'})
35
+ end
36
+
37
+ it 'is non-destructive' do
38
+ expect{ hash.clean(:baz) }.not_to change(hash, :length)
39
+ end
40
+
41
+ it 'ignores absent keys' do
42
+ expect{ hash.clean(:raboof) }.not_to raise_error
43
+ end
44
+
45
+ it 'accepts multiple arguments' do
46
+ expect(hash.clean(:baz, :raboof, :norf)).to eql({:foo => 'bar'})
47
+ end
48
+
49
+ context 'when all keys are bad' do
50
+ it 'returns an empty hash' do
51
+ expect(hash.clean(:foo, :baz)).to eql({})
52
+ end
53
+ end
54
+ end
55
+
56
+ describe 'clean!' do
57
+ it 'removes specified keys' do
58
+ expect(hash.clean!(:baz)).to eql({:foo => 'bar'})
59
+ end
60
+
61
+ it 'is destructive' do
62
+ expect{ hash.clean!(:baz) }.to change(hash, :length)
63
+ end
64
+
65
+ it 'ignores absent keys' do
66
+ expect{ hash.clean!(:raboof) }.not_to raise_error
67
+ end
68
+
69
+ it 'accepts multiple arguments' do
70
+ expect(hash.clean!(:baz, :raboof, :norf)).to eql({:foo => 'bar'})
71
+ end
72
+
73
+ context 'when all keys are bad' do
74
+ it 'returns an empty hash' do
75
+ expect(hash.clean!(:foo, :baz)).to eql({})
76
+ end
77
+ end
78
+ end
79
+
80
+ describe 'only' do
81
+ it 'retains only listed keys' do
82
+ expect(hash.only(:foo)).to eql({:foo => 'bar'})
83
+ end
84
+
85
+ it 'is non-destructive' do
86
+ expect{ hash.only(:foo) }.not_to change(hash, :length)
87
+ end
88
+
89
+ it 'accepts multiple arguments' do
90
+ expect(hash.only(:foo, :baz)).to eql({:foo => 'bar', :baz => 'qux'})
91
+ end
92
+
93
+ context 'when no keys are allowed' do
94
+ it 'returns an empty hash' do
95
+ expect(hash.only(:raboof)).to eql({})
96
+ end
97
+
98
+ it 'doesn\'t raise an error' do
99
+ expect{ hash.only(:raboof) }.not_to raise_error
100
+ end
101
+ end
102
+ end
103
+
104
+ describe 'only!' do
105
+ it 'retains only listed keys' do
106
+ expect(hash.only!(:foo)).to eql({:foo => 'bar'})
107
+ end
108
+
109
+ it 'is destructive' do
110
+ expect{ hash.only!(:foo) }.to change(hash, :keys)
111
+ end
112
+
113
+ it 'accepts multiple arguments' do
114
+ expect(hash.only!(:foo, :baz, :norf)).to eql({:foo => 'bar', :baz => 'qux'})
115
+ end
116
+
117
+ context 'when no keys are allowed' do
118
+ it 'empties the hash' do
119
+ expect(hash.only!(:raboof)).to eql({})
120
+ end
121
+
122
+ it 'doesn\'t raise an error' do
123
+ expect{ hash.only!(:raboof) }.not_to raise_error
124
+ end
125
+ end
126
+ end
127
+
128
+ describe 'standardize' do
129
+ let(:hash) { { :foo => 'bar', :bar => 'baz', :baz => 'qux' } }
130
+
131
+ it 'is non-destructive' do
132
+ expect{ hash.standardize(:foo, :bar) }.not_to change(hash, :keys)
133
+ end
134
+
135
+ context 'exact match' do
136
+ it 'returns the hash as-is' do
137
+ expect(hash.standardize(:foo, :bar, :baz)).to eql hash
138
+ end
139
+ end
140
+
141
+ context 'keys removed' do
142
+ it 'removes keys not given in args' do
143
+ expect(hash.standardize(:foo, :baz)).to eql({:foo => 'bar', :baz => 'qux'})
144
+ end
145
+ end
146
+
147
+ context 'args include keys not present in hash' do
148
+ let(:with_nil) { {:foo => 'bar', :bar => 'baz', :baz => 'qux', :norf => nil } }
149
+
150
+ context 'default' do
151
+ it 'populates with nil values' do
152
+ expect(hash.standardize(:foo, :bar, :baz, :norf)).to eql(with_nil)
153
+ end
154
+
155
+ it 'doesn\'t raise an error' do
156
+ expect{ hash.standardize(:foo, :bar, :baz, :norf) }.not_to raise_error
157
+ end
158
+ end
159
+
160
+ context 'with errors option set to false' do
161
+ it 'populates with nil values' do
162
+ expect(hash.standardize(:foo, :bar, :baz, :norf, :errors => false)).to eql(with_nil)
163
+ end
164
+
165
+ it 'doesn\'t raise an error' do
166
+ expect{ hash.standardize(:foo, :bar, :baz, :norf, :errors => false) }.not_to raise_error
167
+ end
168
+ end
169
+
170
+ context 'with errors option set to true' do
171
+ it 'raises an error' do
172
+ expect{ hash.standardize(:foo, :bar, :baz, :norf, :errors => true) }.to raise_error(ArgumentError)
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ describe 'standardize!' do
179
+ let(:hash) { { :foo => 'bar', :bar => 'baz', :baz => 'qux' } }
180
+
181
+ it 'is destructive' do
182
+ expect{ hash.standardize!(:foo, :bar) }.to change(hash, :keys)
183
+ end
184
+
185
+ context 'exact match' do
186
+ it 'returns the hash as-is' do
187
+ expect(hash.standardize!(:foo, :bar, :baz)).to eql hash
188
+ end
189
+ end
190
+
191
+ context 'keys removed' do
192
+ it 'removes keys not given in args' do
193
+ expect(hash.standardize!(:foo, :baz)).to eql({:foo => 'bar', :baz => 'qux'})
194
+ end
195
+ end
196
+
197
+ context 'args include keys not present in hash' do
198
+ let(:with_nil) { {:foo => 'bar', :bar => 'baz', :baz => 'qux', :norf => nil } }
199
+
200
+ context 'default' do
201
+ it 'populates with nil values' do
202
+ expect(hash.standardize!(:foo, :bar, :baz, :norf)).to eql(with_nil)
203
+ end
204
+
205
+ it 'doesn\'t raise an error' do
206
+ expect{ hash.standardize!(:foo, :bar, :baz, :norf) }.not_to raise_error
207
+ end
208
+ end
209
+
210
+ context 'with errors option set to false' do
211
+ it 'populates with nil values' do
212
+ expect(hash.standardize!(:foo, :bar, :baz, :norf, :errors => false)).to eql(with_nil)
213
+ end
214
+
215
+ it 'doesn\'t raise an error' do
216
+ expect{ hash.standardize!(:foo, :bar, :baz, :norf, :errors => false) }.not_to raise_error
217
+ end
218
+ end
219
+
220
+ context 'wtih errors option set to true' do
221
+ it 'raises an error' do
222
+ expect{ hash.standardize!(:foo, :bar, :baz, :norf, :errors => true) }.to raise_error(ArgumentError)
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ describe 'subset_of?' do
229
+ let(:hash) { {:foo => 'bar', :bar => 'baz', :baz => 'qux'} }
230
+
231
+ context 'when true' do
232
+ it 'returns true' do
233
+ expect({:bar => 'baz'}.subset_of?(hash)).to be true
234
+ end
235
+ end
236
+
237
+ context 'when the calling hash is empty' do
238
+ it 'returns true' do
239
+ expect({}.subset_of?(hash)).to be true
240
+ end
241
+ end
242
+
243
+ context 'when not all keys are shared' do
244
+ it 'returns false' do
245
+ expect({:bar => 'baz', :norf => 'qux'}.subset_of?(hash)).to be false
246
+ end
247
+ end
248
+
249
+ context 'when keys are shared but not values' do
250
+ it 'returns false' do
251
+ expect({:bar => 'foo'}.subset_of?(hash)).to be false
252
+ end
253
+ end
254
+
255
+ context 'when there are no shared keys' do
256
+ it 'returns false' do
257
+ expect({:norf => 'baz'}.subset_of?(hash)).to be false
258
+ end
259
+ end
260
+
261
+ context 'when the hash constitutes a value in a larger hash' do
262
+ it 'returns false' do
263
+ expect(hash.subset_of?({:norf => hash})).to be false
264
+ end
265
+ end
266
+
267
+ context 'when argument is not a hash' do
268
+ it 'raises an error' do
269
+ expect{ hash.subset_of?('foobar') }.to raise_error(ArgumentError)
270
+ end
271
+ end
272
+
273
+ context 'when the calling hash is '
274
+ end
275
+
276
+ describe 'superset_of?' do
277
+ let(:hash) { {:foo => 'bar', :bar => 'baz', :baz => 'qux'} }
278
+
279
+ context 'when true' do
280
+ it 'returns true' do
281
+ expect(hash.superset_of?({:bar => 'baz'})).to be true
282
+ end
283
+ end
284
+
285
+ context 'when the argument hash is empty' do
286
+ it 'returns true' do
287
+ expect(hash.superset_of?({})).to be true
288
+ end
289
+ end
290
+
291
+ context 'when not all keys are shared' do
292
+ it 'returns false' do
293
+ expect(hash.superset_of?({:bar => 'baz', :norf => 'qux'})).to be false
294
+ end
295
+ end
296
+
297
+ context 'when keys are shared but not values' do
298
+ it 'returns false' do
299
+ expect(hash.superset_of?({:bar => 'foo'})).to be false
300
+ end
301
+ end
302
+
303
+ context 'when there are no shared keys' do
304
+ it 'returns false' do
305
+ expect(hash.superset_of?({:norf => 'baz'})).to be false
306
+ end
307
+ end
308
+
309
+ context 'when the hash constitutes a value in a larger hash' do
310
+ it 'returns false' do
311
+ expect({:norf => hash}.superset_of?(hash)).to be false
312
+ end
313
+ end
314
+
315
+ context 'when argument is not a hash' do
316
+ it 'raises an error' do
317
+ expect{ hash.superset_of?('foobar') }.to raise_error(ArgumentError)
318
+ end
319
+ end
320
+ end
321
+ end
data/version.rb CHANGED
@@ -5,9 +5,9 @@ module ReactiveExtensions
5
5
 
6
6
  module Version
7
7
  MAJOR = '0'
8
- MINOR = '4'
8
+ MINOR = '5'
9
9
  PATCH = '0'
10
- PRE = 'beta2'
10
+ PRE = 'beta'
11
11
 
12
12
  STRING = [MAJOR, MINOR, PATCH, PRE].join('.').chomp('.')
13
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reactive_extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0.beta2
4
+ version: 0.5.0.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dana Scheider
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-29 00:00:00.000000000 Z
11
+ date: 2014-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: reactive_support
@@ -116,9 +116,13 @@ extra_rdoc_files:
116
116
  files:
117
117
  - "./lib/reactive_extensions.rb"
118
118
  - "./lib/reactive_extensions/errors.rb"
119
+ - "./lib/reactive_extensions/sanitation.rb"
119
120
  - "./lib/reactive_extensions/scope.rb"
121
+ - "./lib/reactive_extensions/sets.rb"
122
+ - "./lib/reactive_extensions/subtraction.rb"
120
123
  - "./lib/reactive_extensions/try_rescue.rb"
121
124
  - "./spec/array_spec.rb"
125
+ - "./spec/hash_spec.rb"
122
126
  - "./spec/object_spec.rb"
123
127
  - "./spec/proc_spec.rb"
124
128
  - "./spec/spec_helper.rb"