valid_array 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.rdoc +91 -0
- data/lib/typed-array.rb +14 -0
- data/lib/valid_array/functions.rb +111 -0
- data/lib/valid_array/typed_array.rb +74 -0
- data/lib/valid_array.rb +34 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/typed-array_spec.rb +278 -0
- data/spec/typed_array_spec.rb +278 -0
- data/spec/valid_array_spec.rb +45 -0
- metadata +74 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7f027291bafabc6977571d06cae40b0a19a00ed6
|
4
|
+
data.tar.gz: 8c62dab2888b7419ecc7466243ad6b08bfdc67d7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 76bfde39f3b266ad440d05b035f2d91d93d63cd8e0c527f467d33d3d3614fde44f60f4194507d45bd06273a4d5bf51821c14eeb8ed6a0f553618887ea3bbd7dd
|
7
|
+
data.tar.gz: 4b9c64dbd30920a626d8844b92d8b5ec0af9ac9ebcd3ed75374074599d411efc8a3fe98ce6694a16dd4c89b901bf2e1511428431f96c2862c96bc4b21210b737
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2011 Ryan Biesemeyer
|
2
|
+
Copyright (c) 2013 Kevin Cox
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
= valid_array
|
2
|
+
|
3
|
+
The valid_array gem provides to create an Array that enforces certian
|
4
|
+
properties. Each element added to the array is passed to a validator function
|
5
|
+
written by you. This function can raise errors, drop items or change them.
|
6
|
+
|
7
|
+
vaild_array also provides compatibility with the typed-array gem. There is both
|
8
|
+
'valid_array/typed_array' which imports to `ValidArray::TypedArray` and a fully
|
9
|
+
compatible 'valid-array' which passes 'valid-array's own test suite.
|
10
|
+
|
11
|
+
Copyright (c) 2011 Ryan Biesemeyer <mailto:ruby-dev@yaauie.com> (Original typed-array work)
|
12
|
+
Copyright (c) 2013 Kevin Cox <mailto:kevincox@kevincox.ca>
|
13
|
+
See LICENSE for details.
|
14
|
+
|
15
|
+
== Examples
|
16
|
+
|
17
|
+
=== ValidArray
|
18
|
+
|
19
|
+
Valid Array provides a hook to change and validate every element added to the
|
20
|
+
array.
|
21
|
+
|
22
|
+
require 'valid_array'
|
23
|
+
|
24
|
+
# An Array that converts all added elements into strings.
|
25
|
+
class StringArray < Array
|
26
|
+
extend ValidArray
|
27
|
+
|
28
|
+
def self.validate(element)
|
29
|
+
element.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# An array that enforces Numeric types and silently drops odd numbers.
|
34
|
+
class EvenArray < Array
|
35
|
+
extend ValidArray
|
36
|
+
|
37
|
+
class NotEvenException < Exception
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.validate(element)
|
41
|
+
if not element.is_a? Numeric
|
42
|
+
raise TypeError, "Got #{element.class}, expected Numeric!"
|
43
|
+
end
|
44
|
+
|
45
|
+
if element % 2 == 1
|
46
|
+
# This exception is handled by ValidArray, it causes the element to be
|
47
|
+
# dropped. All other exceptions are propagated to the caller.
|
48
|
+
raise ValidArray::DontInsertException
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
=== TypedArray
|
54
|
+
|
55
|
+
TypedArray is fully compatible with https://github.com/yaauie/typed-array/.
|
56
|
+
For compatibility mode require 'typed-array', otherwise require
|
57
|
+
'valid_array/typed_array' and access it from `ValidArray::TypedArray`.
|
58
|
+
|
59
|
+
=== Create Standard Class
|
60
|
+
|
61
|
+
require 'typed-array'
|
62
|
+
class Things < Array
|
63
|
+
extend TypedArray
|
64
|
+
restrict_types Thing1,Thing2
|
65
|
+
end
|
66
|
+
|
67
|
+
# or new style
|
68
|
+
|
69
|
+
require 'valid_array/typed_array'
|
70
|
+
class Things < Array
|
71
|
+
extend ValidArray::TypedArray
|
72
|
+
restrict_types Thing1,Thing2
|
73
|
+
end
|
74
|
+
|
75
|
+
=== Generate Class using Factory
|
76
|
+
|
77
|
+
require 'typed-array'
|
78
|
+
things = TypedArray(Thing1,Thing2)
|
79
|
+
a = things.new
|
80
|
+
|
81
|
+
# or new style
|
82
|
+
|
83
|
+
require 'valid_array/typed_array'
|
84
|
+
things = ValidArray::TypedArray(Thing1, Thing2)
|
85
|
+
a = things.new
|
86
|
+
|
87
|
+
= Adding items to the Array
|
88
|
+
|
89
|
+
All standard Array interfaces are implemented, including block-processing
|
90
|
+
and variable-number of arguments. For methods that would usually return an
|
91
|
+
Array, they instead return an instance of the current class (except to_a).
|
data/lib/typed-array.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Provides compatibility with https://github.com/yaauie/typed-array
|
2
|
+
|
3
|
+
require 'valid_array/typed_array'
|
4
|
+
|
5
|
+
# Alias for compatibility.
|
6
|
+
# see {ValidArray::TypedArray}
|
7
|
+
TypedArray = ValidArray::TypedArray
|
8
|
+
|
9
|
+
|
10
|
+
# Alias for compatibility.
|
11
|
+
# see {ValidArray::TypedArray}
|
12
|
+
def TypedArray(*args)
|
13
|
+
ValidArray::TypedArray *args
|
14
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# Provides the validation functions that get included into a ValidArray
|
2
|
+
|
3
|
+
# Namespace ValidArray
|
4
|
+
module ValidArray
|
5
|
+
|
6
|
+
# The functions that get included into ValidArray
|
7
|
+
module Functions
|
8
|
+
# Validates outcome. See Array#initialize
|
9
|
+
def initialize(*args, &block)
|
10
|
+
ary = Array.new *args, &block
|
11
|
+
self.replace ary
|
12
|
+
end
|
13
|
+
|
14
|
+
# Validates outcome. See Array#replace
|
15
|
+
def replace(other_ary)
|
16
|
+
other_ary = _ensure_array_is_valid other_ary
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
# Validates outcome. See Array#&
|
21
|
+
def &(ary)
|
22
|
+
self.class.new super
|
23
|
+
end
|
24
|
+
|
25
|
+
# Validates outcome. See Array#*
|
26
|
+
def *(int)
|
27
|
+
self.class.new super
|
28
|
+
end
|
29
|
+
|
30
|
+
# Validates outcome. See Array#+
|
31
|
+
def +(ary)
|
32
|
+
self.class.new super
|
33
|
+
end
|
34
|
+
|
35
|
+
# Validates outcome. See Array#<<
|
36
|
+
def <<(item)
|
37
|
+
begin
|
38
|
+
item = self.class.validate item
|
39
|
+
super
|
40
|
+
rescue DontInsertException; end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Validates outcome. See Array#[]
|
44
|
+
def [](idx)
|
45
|
+
self.class.new super
|
46
|
+
end
|
47
|
+
|
48
|
+
# Validates outcome. See Array#slice
|
49
|
+
def slice(*args)
|
50
|
+
self.class.new super
|
51
|
+
end
|
52
|
+
|
53
|
+
# Validates outcome. See Array#[]=
|
54
|
+
def []=(idx, item)
|
55
|
+
begin
|
56
|
+
item = self.class.validate item
|
57
|
+
super
|
58
|
+
rescue DontInsertException; end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Validates outcome. See Array#concat
|
62
|
+
def concat(other_ary)
|
63
|
+
_ensure_array_is_valid other_ary
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
# Validates outcome. See Array#eql?
|
68
|
+
#def eql?(other_ary)
|
69
|
+
# _ensure_all_items_in_array_are_allowed other_ary
|
70
|
+
# super
|
71
|
+
#end
|
72
|
+
|
73
|
+
# Validates outcome. See Array#fill
|
74
|
+
def fill(*args, &block)
|
75
|
+
ary = self.to_a
|
76
|
+
ary.fill *args, &block
|
77
|
+
self.replace ary
|
78
|
+
end
|
79
|
+
|
80
|
+
# Validates outcome. See Array#push
|
81
|
+
def push(*items)
|
82
|
+
items = _ensure_array_is_valid items
|
83
|
+
super
|
84
|
+
end
|
85
|
+
|
86
|
+
# Validates outcome. See Array#unshift
|
87
|
+
def unshift(*items)
|
88
|
+
items = _ensure_array_is_valid items
|
89
|
+
super
|
90
|
+
end
|
91
|
+
|
92
|
+
# Validates outcome. See Array#map!
|
93
|
+
def map!(&block)
|
94
|
+
self.replace(self.map &block)
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
# Ensure that all items in the passed Array are allowed
|
100
|
+
def _ensure_array_is_valid(ary)
|
101
|
+
toins = []
|
102
|
+
ary.each do |e|
|
103
|
+
begin
|
104
|
+
toins << self.class.validate(e)
|
105
|
+
rescue DontInsertException; end
|
106
|
+
end
|
107
|
+
|
108
|
+
toins
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# :include: ../README.rdoc
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require 'valid_array'
|
5
|
+
|
6
|
+
# Provides ValidArray functionality to a subclass of Array
|
7
|
+
# when extended in the class's definiton
|
8
|
+
module ValidArray::TypedArray
|
9
|
+
# when a class inherits from this one, make sure that it also inherits
|
10
|
+
# the types that are being enforced
|
11
|
+
def inherited(subclass)
|
12
|
+
self._subclasses << subclass
|
13
|
+
subclass.restricted_types *self.restricted_types
|
14
|
+
end
|
15
|
+
|
16
|
+
# A getter/setter for types to add. If no arguments are passed, it simply
|
17
|
+
# returns the current array of accepted types.
|
18
|
+
def restricted_types(*types)
|
19
|
+
@_restricted_types ||= []
|
20
|
+
types.each do |type|
|
21
|
+
raise UnexpectedTypeException.new([Class],type.class) unless type.is_a? Class
|
22
|
+
@_restricted_types << type unless @_restricted_types.include? type
|
23
|
+
_subclasses.each do |subclass|
|
24
|
+
subclass.restricted_types type
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@_restricted_types
|
28
|
+
end; alias :restricted_type :restricted_types
|
29
|
+
|
30
|
+
|
31
|
+
# The exception that is raised when an Unexpected Type is reached during validation
|
32
|
+
class UnexpectedTypeException < Exception
|
33
|
+
# Provide access to the types of objects expected and the class of the object received
|
34
|
+
attr_reader :expected, :received
|
35
|
+
|
36
|
+
def initialize(expected_one_of, received)
|
37
|
+
@expected = expected_one_of
|
38
|
+
@received = received
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
%{Expected one of #{@expected.inspect} but received a(n) #{@received}}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate(item)
|
47
|
+
if item.nil? or restricted_types.any? { |allowed| item.class <= allowed }
|
48
|
+
return item
|
49
|
+
else
|
50
|
+
raise TypedArray::UnexpectedTypeException.new(restricted_types, item.class)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
# a store of subclasses
|
57
|
+
def _subclasses
|
58
|
+
@_subclasses ||= []
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
# Provide a factory method. Takes any number of types to accept as arguments
|
64
|
+
# and returns a class that behaves as a type-enforced array.
|
65
|
+
def ValidArray::TypedArray(*types_allowed)
|
66
|
+
klass = Class.new( Array )
|
67
|
+
klass.class_exec(types_allowed) do |types_allowed|
|
68
|
+
extend ValidArray
|
69
|
+
extend TypedArray
|
70
|
+
|
71
|
+
restricted_types *types_allowed
|
72
|
+
end
|
73
|
+
klass
|
74
|
+
end
|
data/lib/valid_array.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# :include: ../README.rdoc
|
2
|
+
|
3
|
+
require 'valid_array/functions'
|
4
|
+
|
5
|
+
# Provides ValidArray functionality to a subclass of Array
|
6
|
+
# when extended in the class's definiton
|
7
|
+
module ValidArray
|
8
|
+
# Hook the extension process in order to include the necessary functions
|
9
|
+
# and do some basic sanity checks.
|
10
|
+
def self.extended(mod)
|
11
|
+
mod.module_exec(self::Functions) do |functions_module|
|
12
|
+
include functions_module
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Exception to raise to silently skip insertion.
|
17
|
+
#
|
18
|
+
# Raising this from validate will prevent the item from being inserted. Use
|
19
|
+
# with caution as it may break assumptions that coders are making about how
|
20
|
+
# your array works.
|
21
|
+
class DontInsertException < Exception; end
|
22
|
+
|
23
|
+
# Default validator. Override this.
|
24
|
+
#
|
25
|
+
# Translates the provided item to insert to the new item. Raise an exception
|
26
|
+
# to prevent insertion. DontInsertException will be handled and ignored,
|
27
|
+
# other exceptions will be propergated.
|
28
|
+
#
|
29
|
+
# @param element [Object] The element being added to the array.
|
30
|
+
# @return [Object] The element to actualy insert into the array.
|
31
|
+
def validate(element)
|
32
|
+
raise NotImplementedError, "You must implement validate."
|
33
|
+
end
|
34
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'typed-array'
|
3
|
+
|
4
|
+
# We need to test in several different contexts, so provide the base info here.
|
5
|
+
inputs = {
|
6
|
+
[Symbol]=>{
|
7
|
+
:base => [:foo,:bar],
|
8
|
+
:match => [:baz,:bingo],
|
9
|
+
:fail => {
|
10
|
+
:one => [:zip,0],
|
11
|
+
:all => ['string',Class]
|
12
|
+
}
|
13
|
+
},
|
14
|
+
[Fixnum] => {
|
15
|
+
:base => [ 1,2,3 ],
|
16
|
+
:match => [ 17,18,19 ],
|
17
|
+
:fail => {
|
18
|
+
:one => [22,:symbol,43],
|
19
|
+
:all => ['string',:symbol]
|
20
|
+
}
|
21
|
+
},
|
22
|
+
[String,Symbol] => {
|
23
|
+
:base => ['Foo',:foo],
|
24
|
+
:match => [:bar,'Bar'],
|
25
|
+
:fail => {
|
26
|
+
:one => [:yippee,'a string',17],
|
27
|
+
:all => [12,Class,Array]
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
describe TypedArray do
|
33
|
+
describe '#new' do
|
34
|
+
inputs.each_pair do |accepted_types, config|
|
35
|
+
context "when only accepting <#{accepted_types.inspect}>" do
|
36
|
+
subject { TypedArray( *accepted_types ) }
|
37
|
+
|
38
|
+
context 'Form 1: typed_ary.new()' do
|
39
|
+
it "should have zero-length" do
|
40
|
+
subject.new().length.should == 0
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should be empty" do
|
44
|
+
subject.new().to_a.should be_empty
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'Form 1: typed_ary.new(size)' do
|
49
|
+
it "should have the proper length" do
|
50
|
+
subject.new(5).length.should == 5
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should conatin all nil values" do
|
54
|
+
subject.new(5).to_a.should == [nil,nil,nil,nil,nil]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'Form 2: typed_ary.new(size,object)' do
|
59
|
+
it "should have the proper length" do
|
60
|
+
subject.new(3,config[:match].first).length.should == 3
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should conatin the value specified" do
|
64
|
+
subject.new(3,config[:match].first).to_a.should == [config[:match].first]*3
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should raise when obj is the wrong type" do
|
68
|
+
expect{ subject.new( 3, config[:fail][:all].first ) }.to raise_error TypedArray::UnexpectedTypeException
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'Form 3: typed_ary.new( ary )' do
|
73
|
+
it "should accept when all items match" do
|
74
|
+
subject.new(config[:match]).to_a.should == config[:match]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should raise when one object is the wrong type" do
|
78
|
+
expect{ subject.new(config[:fail][:one])}.to raise_error TypedArray::UnexpectedTypeException
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should raise when more than one object is the wrong type" do
|
82
|
+
expect{ subject.new(config[:fail][:all])}.to raise_error TypedArray::UnexpectedTypeException
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'Form 4: typed_ary.new(size){|index|block}' do
|
87
|
+
it "should populate when block returns the right type" do
|
88
|
+
subject.new(config[:match].length){|i| config[:match][i]}.to_a.should == config[:match]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should raise when block returns wrong type once" do
|
92
|
+
expect{ subject.new(config[:fail][:one].length){|i| config[:fail][:one][i]} }.to raise_error TypedArray::UnexpectedTypeException
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should raise when block returns wrong type more than once" do
|
96
|
+
expect{ subject.new(config[:fail][:all].length){|i| config[:fail][:all][i]} }.to raise_error TypedArray::UnexpectedTypeException
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
[:<<,:unshift,:push].each do |method|
|
104
|
+
context %Q{typed_ary#{('a'..'z').include?(method.to_s[0]) ? '.' : ' '}#{method.to_s} other_ary} do
|
105
|
+
inputs.each_pair do |accepted_types,config|
|
106
|
+
context "when only accepting <#{accepted_types.inspect}>" do
|
107
|
+
before :each do
|
108
|
+
@typed_ary = TypedArray( *accepted_types).new(config[:base])
|
109
|
+
@ary = config[:base].to_a
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when the item being pushed matches (#{config[:match].first})" do
|
113
|
+
before :each do
|
114
|
+
@item = config[:match].first
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should return as Array would return" do
|
118
|
+
@typed_ary.send(method,@item).to_a.should == @ary.send(method,@item)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should modify the TypedArray as Array would be modified" do
|
122
|
+
@typed_ary.send(method,@item)
|
123
|
+
@ary.send(method,@item)
|
124
|
+
@typed_ary.to_a.should == @ary
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when the item being pushed does not match (#{config[:fail][:all].first})" do
|
129
|
+
before :each do
|
130
|
+
@item = config[:fail][:all].first
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should raise an exception" do
|
134
|
+
expect{ @typed_ary.send(method,@item) }.to raise_error TypedArray::UnexpectedTypeException
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not modify typed_ary" do
|
138
|
+
begin
|
139
|
+
backup = @typed_ary.to_a
|
140
|
+
@typed_ary.send(method,@item)
|
141
|
+
rescue TypedArray::UnexpectedTypeException
|
142
|
+
ensure
|
143
|
+
@typed_ary.to_a.should == backup
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
[:[]=].each do |method|
|
153
|
+
context %Q{typed_ary[idx]= other_ary} do
|
154
|
+
inputs.each_pair do |accepted_types,config|
|
155
|
+
context "when only accepting <#{accepted_types.inspect}>" do
|
156
|
+
before :each do
|
157
|
+
@typed_ary = TypedArray( *accepted_types).new(config[:base])
|
158
|
+
@ary = config[:base].to_a
|
159
|
+
end
|
160
|
+
|
161
|
+
context "when the item being pushed matches (#{config[:match].first})" do
|
162
|
+
before :each do
|
163
|
+
@item = config[:match].first
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should return as Array would return" do
|
167
|
+
@typed_ary.send(method,4,@item).should == @ary.send(method,4,@item)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should modify the TypedArray as Array would be modified" do
|
171
|
+
@typed_ary.send(method,4,@item)
|
172
|
+
@ary.send(method,4,@item)
|
173
|
+
@typed_ary.to_a.should == @ary
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context "when the item being pushed does not match (#{config[:fail][:all].first})" do
|
178
|
+
before :each do
|
179
|
+
@item = config[:fail][:all].first
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should raise an exception" do
|
183
|
+
|
184
|
+
expect{ @typed_ary.send(method,4,@item) }.to raise_error TypedArray::UnexpectedTypeException
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should not modify typed_ary" do
|
188
|
+
begin
|
189
|
+
backup = @typed_ary.to_a
|
190
|
+
@typed_ary.send(method,4,@item)
|
191
|
+
rescue TypedArray::UnexpectedTypeException
|
192
|
+
ensure
|
193
|
+
@typed_ary.to_a.should == backup
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
[:+,:&,:concat,:replace].each do |method|
|
203
|
+
context %Q{typed_ary#{('a'..'z').include?(method.to_s[0]) ? '.' : ' '}#{method.to_s} other_ary} do
|
204
|
+
inputs.each_pair do |accepted_types,config|
|
205
|
+
context "when only accepting <#{accepted_types.inspect}>" do
|
206
|
+
before :each do
|
207
|
+
@typed_ary = TypedArray( *accepted_types).new(config[:base])
|
208
|
+
@ary = config[:base].to_a
|
209
|
+
end
|
210
|
+
|
211
|
+
context "when all items match (#{config[:match].inspect})" do
|
212
|
+
before :each do
|
213
|
+
@other_ary = config[:match].to_a
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should return as Array would return" do
|
217
|
+
@typed_ary.send(method,@other_ary).to_a.should == @ary.send(method,@other_ary)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should modify the TypedArray as Array would be modified" do
|
221
|
+
@typed_ary.send(method,@other_ary)
|
222
|
+
@ary.send(method,@other_ary)
|
223
|
+
@typed_ary.to_a.should == @ary
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
config[:fail].each_key do |fail_type|
|
228
|
+
context "when #{fail_type} item fails to match (#{config[:fail][fail_type].inspect})" do
|
229
|
+
before :each do
|
230
|
+
@other_ary = config[:fail][fail_type].to_a
|
231
|
+
end
|
232
|
+
unless method == :& # `and` opperator cannot produce elements that are not in both arrays already; since one is assuredly filtered, we can skip this.
|
233
|
+
it "should raise an exception" do
|
234
|
+
expect{ @typed_ary.send(method,@other_ary) }.to raise_error TypedArray::UnexpectedTypeException
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should not modify the TypedArray" do
|
239
|
+
begin
|
240
|
+
backup = @typed_ary.to_a
|
241
|
+
@typed_ary.send(method,@other_ary)
|
242
|
+
rescue TypedArray::UnexpectedTypeException
|
243
|
+
ensure
|
244
|
+
@typed_ary.to_a.should == backup
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'when extending classes' do
|
255
|
+
before :each do
|
256
|
+
@base = TypedArray(Symbol)
|
257
|
+
@extension = Class.new( @base )
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'should inherit default restrictions' do
|
261
|
+
@base.restricted_types.should == @extension.restricted_types
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'when adding restricted_type to the parent' do
|
265
|
+
it 'should propogate to the child' do
|
266
|
+
@base.restricted_type Fixnum
|
267
|
+
@extension.restricted_types.should include(Fixnum)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
context 'when adding restricted_type to the child' do
|
272
|
+
it 'should not propogate to the parent' do
|
273
|
+
@extension.restricted_type Fixnum
|
274
|
+
@base.restricted_types.should_not include(Fixnum)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'valid_array/typed_array'
|
3
|
+
|
4
|
+
# We need to test in several different contexts, so provide the base info here.
|
5
|
+
inputs = {
|
6
|
+
[Symbol]=>{
|
7
|
+
:base => [:foo,:bar],
|
8
|
+
:match => [:baz,:bingo],
|
9
|
+
:fail => {
|
10
|
+
:one => [:zip,0],
|
11
|
+
:all => ['string',Class]
|
12
|
+
}
|
13
|
+
},
|
14
|
+
[Fixnum] => {
|
15
|
+
:base => [ 1,2,3 ],
|
16
|
+
:match => [ 17,18,19 ],
|
17
|
+
:fail => {
|
18
|
+
:one => [22,:symbol,43],
|
19
|
+
:all => ['string',:symbol]
|
20
|
+
}
|
21
|
+
},
|
22
|
+
[String,Symbol] => {
|
23
|
+
:base => ['Foo',:foo],
|
24
|
+
:match => [:bar,'Bar'],
|
25
|
+
:fail => {
|
26
|
+
:one => [:yippee,'a string',17],
|
27
|
+
:all => [12,Class,Array]
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
describe ValidArray::TypedArray do
|
33
|
+
describe '#new' do
|
34
|
+
inputs.each_pair do |accepted_types, config|
|
35
|
+
context "when only accepting <#{accepted_types.inspect}>" do
|
36
|
+
subject { ValidArray::TypedArray( *accepted_types ) }
|
37
|
+
|
38
|
+
context 'Form 1: typed_ary.new()' do
|
39
|
+
it "should have zero-length" do
|
40
|
+
subject.new().length.should == 0
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should be empty" do
|
44
|
+
subject.new().to_a.should be_empty
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'Form 1: typed_ary.new(size)' do
|
49
|
+
it "should have the proper length" do
|
50
|
+
subject.new(5).length.should == 5
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should conatin all nil values" do
|
54
|
+
subject.new(5).to_a.should == [nil,nil,nil,nil,nil]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'Form 2: typed_ary.new(size,object)' do
|
59
|
+
it "should have the proper length" do
|
60
|
+
subject.new(3,config[:match].first).length.should == 3
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should conatin the value specified" do
|
64
|
+
subject.new(3,config[:match].first).to_a.should == [config[:match].first]*3
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should raise when obj is the wrong type" do
|
68
|
+
expect{ subject.new( 3, config[:fail][:all].first ) }.to raise_error ValidArray::TypedArray::UnexpectedTypeException
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'Form 3: typed_ary.new( ary )' do
|
73
|
+
it "should accept when all items match" do
|
74
|
+
subject.new(config[:match]).to_a.should == config[:match]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should raise when one object is the wrong type" do
|
78
|
+
expect{ subject.new(config[:fail][:one])}.to raise_error ValidArray::TypedArray::UnexpectedTypeException
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should raise when more than one object is the wrong type" do
|
82
|
+
expect{ subject.new(config[:fail][:all])}.to raise_error ValidArray::TypedArray::UnexpectedTypeException
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'Form 4: typed_ary.new(size){|index|block}' do
|
87
|
+
it "should populate when block returns the right type" do
|
88
|
+
subject.new(config[:match].length){|i| config[:match][i]}.to_a.should == config[:match]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should raise when block returns wrong type once" do
|
92
|
+
expect{ subject.new(config[:fail][:one].length){|i| config[:fail][:one][i]} }.to raise_error ValidArray::TypedArray::UnexpectedTypeException
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should raise when block returns wrong type more than once" do
|
96
|
+
expect{ subject.new(config[:fail][:all].length){|i| config[:fail][:all][i]} }.to raise_error ValidArray::TypedArray::UnexpectedTypeException
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
[:<<,:unshift,:push].each do |method|
|
104
|
+
context %Q{typed_ary#{('a'..'z').include?(method.to_s[0]) ? '.' : ' '}#{method.to_s} other_ary} do
|
105
|
+
inputs.each_pair do |accepted_types,config|
|
106
|
+
context "when only accepting <#{accepted_types.inspect}>" do
|
107
|
+
before :each do
|
108
|
+
@typed_ary = ValidArray::TypedArray( *accepted_types).new(config[:base])
|
109
|
+
@ary = config[:base].to_a
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when the item being pushed matches (#{config[:match].first})" do
|
113
|
+
before :each do
|
114
|
+
@item = config[:match].first
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should return as Array would return" do
|
118
|
+
@typed_ary.send(method,@item).to_a.should == @ary.send(method,@item)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should modify the TypedArray as Array would be modified" do
|
122
|
+
@typed_ary.send(method,@item)
|
123
|
+
@ary.send(method,@item)
|
124
|
+
@typed_ary.to_a.should == @ary
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when the item being pushed does not match (#{config[:fail][:all].first})" do
|
129
|
+
before :each do
|
130
|
+
@item = config[:fail][:all].first
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should raise an exception" do
|
134
|
+
expect{ @typed_ary.send(method,@item) }.to raise_error ValidArray::TypedArray::UnexpectedTypeException
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not modify typed_ary" do
|
138
|
+
begin
|
139
|
+
backup = @typed_ary.to_a
|
140
|
+
@typed_ary.send(method,@item)
|
141
|
+
rescue ValidArray::TypedArray::UnexpectedTypeException
|
142
|
+
ensure
|
143
|
+
@typed_ary.to_a.should == backup
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
[:[]=].each do |method|
|
153
|
+
context %Q{typed_ary[idx]= other_ary} do
|
154
|
+
inputs.each_pair do |accepted_types,config|
|
155
|
+
context "when only accepting <#{accepted_types.inspect}>" do
|
156
|
+
before :each do
|
157
|
+
@typed_ary = ValidArray::TypedArray( *accepted_types).new(config[:base])
|
158
|
+
@ary = config[:base].to_a
|
159
|
+
end
|
160
|
+
|
161
|
+
context "when the item being pushed matches (#{config[:match].first})" do
|
162
|
+
before :each do
|
163
|
+
@item = config[:match].first
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should return as Array would return" do
|
167
|
+
@typed_ary.send(method,4,@item).should == @ary.send(method,4,@item)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should modify the TypedArray as Array would be modified" do
|
171
|
+
@typed_ary.send(method,4,@item)
|
172
|
+
@ary.send(method,4,@item)
|
173
|
+
@typed_ary.to_a.should == @ary
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context "when the item being pushed does not match (#{config[:fail][:all].first})" do
|
178
|
+
before :each do
|
179
|
+
@item = config[:fail][:all].first
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should raise an exception" do
|
183
|
+
|
184
|
+
expect{ @typed_ary.send(method,4,@item) }.to raise_error ValidArray::TypedArray::UnexpectedTypeException
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should not modify typed_ary" do
|
188
|
+
begin
|
189
|
+
backup = @typed_ary.to_a
|
190
|
+
@typed_ary.send(method,4,@item)
|
191
|
+
rescue ValidArray::TypedArray::UnexpectedTypeException
|
192
|
+
ensure
|
193
|
+
@typed_ary.to_a.should == backup
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
[:+,:&,:concat,:replace].each do |method|
|
203
|
+
context %Q{typed_ary#{('a'..'z').include?(method.to_s[0]) ? '.' : ' '}#{method.to_s} other_ary} do
|
204
|
+
inputs.each_pair do |accepted_types,config|
|
205
|
+
context "when only accepting <#{accepted_types.inspect}>" do
|
206
|
+
before :each do
|
207
|
+
@typed_ary = ValidArray::TypedArray( *accepted_types).new(config[:base])
|
208
|
+
@ary = config[:base].to_a
|
209
|
+
end
|
210
|
+
|
211
|
+
context "when all items match (#{config[:match].inspect})" do
|
212
|
+
before :each do
|
213
|
+
@other_ary = config[:match].to_a
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should return as Array would return" do
|
217
|
+
@typed_ary.send(method,@other_ary).to_a.should == @ary.send(method,@other_ary)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should modify the TypedArray as Array would be modified" do
|
221
|
+
@typed_ary.send(method,@other_ary)
|
222
|
+
@ary.send(method,@other_ary)
|
223
|
+
@typed_ary.to_a.should == @ary
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
config[:fail].each_key do |fail_type|
|
228
|
+
context "when #{fail_type} item fails to match (#{config[:fail][fail_type].inspect})" do
|
229
|
+
before :each do
|
230
|
+
@other_ary = config[:fail][fail_type].to_a
|
231
|
+
end
|
232
|
+
unless method == :& # `and` opperator cannot produce elements that are not in both arrays already; since one is assuredly filtered, we can skip this.
|
233
|
+
it "should raise an exception" do
|
234
|
+
expect{ @typed_ary.send(method,@other_ary) }.to raise_error ValidArray::TypedArray::UnexpectedTypeException
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should not modify the TypedArray" do
|
239
|
+
begin
|
240
|
+
backup = @typed_ary.to_a
|
241
|
+
@typed_ary.send(method,@other_ary)
|
242
|
+
rescue ValidArray::TypedArray::UnexpectedTypeException
|
243
|
+
ensure
|
244
|
+
@typed_ary.to_a.should == backup
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'when extending classes' do
|
255
|
+
before :each do
|
256
|
+
@base = ValidArray::TypedArray(Symbol)
|
257
|
+
@extension = Class.new( @base )
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'should inherit default restrictions' do
|
261
|
+
@base.restricted_types.should == @extension.restricted_types
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'when adding restricted_type to the parent' do
|
265
|
+
it 'should propogate to the child' do
|
266
|
+
@base.restricted_type Fixnum
|
267
|
+
@extension.restricted_types.should include(Fixnum)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
context 'when adding restricted_type to the child' do
|
272
|
+
it 'should not propogate to the parent' do
|
273
|
+
@extension.restricted_type Fixnum
|
274
|
+
@base.restricted_types.should_not include(Fixnum)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'valid_array'
|
3
|
+
|
4
|
+
describe ValidArray do
|
5
|
+
context 'when custom validator is used' do
|
6
|
+
before :each do
|
7
|
+
class MyArray < Array
|
8
|
+
extend ValidArray
|
9
|
+
|
10
|
+
def self.validate(e)
|
11
|
+
e.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
@typed_ary = MyArray.new(5) {|i| i}
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should convert all values to strings' do
|
18
|
+
@typed_ary.each do |e|
|
19
|
+
e.should be_an_instance_of(String)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when custom validator is used' do
|
25
|
+
before :each do
|
26
|
+
class MyArray < Array
|
27
|
+
extend ValidArray
|
28
|
+
|
29
|
+
def self.validate(e)
|
30
|
+
if e%2 == 0
|
31
|
+
e
|
32
|
+
else
|
33
|
+
raise ValidArray::DontInsertException
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
@typed_ary = MyArray.new(10) {|i| i}
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should drop when DontInsertException is raised' do
|
42
|
+
@typed_ary.should eql([0,2,4,6,8])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: valid_array
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kevin Cox
|
8
|
+
- Ryan Biesemeyer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-08-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rdoc
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '3.9'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '3.9'
|
28
|
+
description: "\t\tAll methods that alter the contents of an array that implements
|
29
|
+
this\n\t\tGem are first checked to ensure that the added items are of the types\n\t\tallowed.
|
30
|
+
All methods behave exactly as their Array counterparts,\n\t\tincluding additional
|
31
|
+
forms, block processing, etc.\n"
|
32
|
+
email: kevincox@kevincox.ca
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files:
|
36
|
+
- LICENSE
|
37
|
+
- README.rdoc
|
38
|
+
files:
|
39
|
+
- lib/valid_array.rb
|
40
|
+
- lib/valid_array/typed_array.rb
|
41
|
+
- lib/valid_array/functions.rb
|
42
|
+
- lib/typed-array.rb
|
43
|
+
- spec/spec_helper.rb
|
44
|
+
- spec/valid_array_spec.rb
|
45
|
+
- spec/typed-array_spec.rb
|
46
|
+
- spec/typed_array_spec.rb
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
homepage: http://github.com/kevincox/valid-array
|
50
|
+
licenses:
|
51
|
+
- MIT
|
52
|
+
metadata: {}
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 2.0.3
|
70
|
+
signing_key:
|
71
|
+
specification_version: 1
|
72
|
+
summary: Provides methods for creating type-enforced Arrays
|
73
|
+
test_files: []
|
74
|
+
has_rdoc:
|