reactive_extensions 0.4.0.beta2 → 0.5.0.beta

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: 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"