corefoundation 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +8 -0
- data/README.md +39 -0
- data/lib/corefoundation.rb +11 -0
- data/lib/corefoundation/array.rb +123 -0
- data/lib/corefoundation/base.rb +197 -0
- data/lib/corefoundation/boolean.rb +25 -0
- data/lib/corefoundation/data.rb +38 -0
- data/lib/corefoundation/date.rb +32 -0
- data/lib/corefoundation/dictionary.rb +114 -0
- data/lib/corefoundation/extensions.rb +81 -0
- data/lib/corefoundation/null.rb +11 -0
- data/lib/corefoundation/number.rb +98 -0
- data/lib/corefoundation/string.rb +77 -0
- data/lib/corefoundation/version.rb +4 -0
- data/spec/array_spec.rb +92 -0
- data/spec/boolean_spec.rb +24 -0
- data/spec/data_spec.rb +26 -0
- data/spec/date_spec.rb +25 -0
- data/spec/dictionary_spec.rb +81 -0
- data/spec/extensions_spec.rb +63 -0
- data/spec/null_spec.rb +7 -0
- data/spec/number_spec.rb +52 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/string_spec.rb +39 -0
- metadata +150 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
module CF
|
2
|
+
typedef :pointer, :cfdateref
|
3
|
+
typedef :double, :cfabsolutetime
|
4
|
+
|
5
|
+
attach_function :CFDateCreate, [:pointer, :cfabsolutetime], :cfdateref
|
6
|
+
attach_function :CFDateGetAbsoluteTime, [:cfdateref], :cfabsolutetime
|
7
|
+
attach_variable :kCFAbsoluteTimeIntervalSince1970, :double
|
8
|
+
|
9
|
+
# Wrapper for CFDateRef
|
10
|
+
#
|
11
|
+
#
|
12
|
+
class Date < Base
|
13
|
+
register_type 'CFDate'
|
14
|
+
|
15
|
+
# constructs a CF::Date from a ruby time
|
16
|
+
#
|
17
|
+
# @param [Time] time
|
18
|
+
# @return [CF::Date] a CF::Date instance that will be released on garbage collection
|
19
|
+
def self.from_time(time)
|
20
|
+
new(CF.CFDateCreate(nil, time.to_f - CF.kCFAbsoluteTimeIntervalSince1970)).release_on_gc
|
21
|
+
end
|
22
|
+
|
23
|
+
# returns a ruby Time instance corresponding to the same point in time
|
24
|
+
#
|
25
|
+
# @return [Time]
|
26
|
+
def to_time
|
27
|
+
Time.at(CF.CFDateGetAbsoluteTime(self) + CF.kCFAbsoluteTimeIntervalSince1970)
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :to_ruby, :to_time
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module CF
|
2
|
+
# @private
|
3
|
+
class DictionaryKeyCallbacks < FFI::Struct
|
4
|
+
layout :version, :cfindex,
|
5
|
+
:retain, :pointer,
|
6
|
+
:release, :pointer,
|
7
|
+
:copyDescription, :pointer,
|
8
|
+
:equal, :pointer,
|
9
|
+
:hash, :pointer
|
10
|
+
end
|
11
|
+
# @private
|
12
|
+
class DictionaryValueCallbacks < FFI::Struct
|
13
|
+
layout :version, :cfindex,
|
14
|
+
:retain, :pointer,
|
15
|
+
:release, :pointer,
|
16
|
+
:copyDescription, :pointer,
|
17
|
+
:equal, :pointer
|
18
|
+
end
|
19
|
+
|
20
|
+
typedef :pointer, :cfdictionaryref
|
21
|
+
attach_variable :kCFTypeDictionaryKeyCallBacks, DictionaryKeyCallbacks
|
22
|
+
attach_variable :kCFTypeDictionaryValueCallBacks, DictionaryValueCallbacks
|
23
|
+
attach_function :CFDictionaryCreateMutable, [:pointer, :cfindex, :pointer, :pointer], :cfdictionaryref
|
24
|
+
|
25
|
+
attach_function :CFDictionarySetValue, [:cfdictionaryref, :pointer, :pointer], :void
|
26
|
+
attach_function :CFDictionaryGetValue, [:cfdictionaryref, :pointer], :pointer
|
27
|
+
|
28
|
+
attach_function :CFDictionaryGetValue, [:cfdictionaryref, :pointer], :pointer
|
29
|
+
attach_function :CFDictionaryGetCount, [:cfdictionaryref], :cfindex
|
30
|
+
|
31
|
+
callback :each_applier, [:pointer, :pointer, :pointer], :void
|
32
|
+
|
33
|
+
attach_function :CFDictionaryApplyFunction, [:cfdictionaryref, :each_applier, :pointer], :void
|
34
|
+
|
35
|
+
# Wrapper class for CFDictionary. It implements Enumerable.
|
36
|
+
#
|
37
|
+
# Values returned by the accessor methods or yielded by the block are retained and marked as releasable on garbage collection
|
38
|
+
# This means you can safely use the returned values even if the CFDictionary itself has been destroyed
|
39
|
+
#
|
40
|
+
class Dictionary < Base
|
41
|
+
register_type("CFDictionary")
|
42
|
+
include Enumerable
|
43
|
+
|
44
|
+
# Return a new, empty mutable CF::Dictionary
|
45
|
+
#
|
46
|
+
#
|
47
|
+
# @return [CF::Dictionary]
|
48
|
+
def self.mutable
|
49
|
+
new(CF.CFDictionaryCreateMutable nil, 0, CF.kCFTypeDictionaryKeyCallBacks.to_ptr, CF.kCFTypeDictionaryValueCallBacks.to_ptr).release_on_gc
|
50
|
+
end
|
51
|
+
|
52
|
+
# Iterates over the array yielding the value to the block
|
53
|
+
# The value is wrapped in the appropriate CF::Base subclass and retained (but marked for releasing upon garbage collection)
|
54
|
+
# @return self
|
55
|
+
|
56
|
+
def each
|
57
|
+
callback = lambda do |key, value, _|
|
58
|
+
yield [Base.typecast(key).retain.release_on_gc, Base.typecast(value).retain.release_on_gc]
|
59
|
+
end
|
60
|
+
CF.CFDictionaryApplyFunction(self, callback, nil)
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the value associated with the key, or nil
|
65
|
+
# The key should be a CF::Base instance. As a convenience, instances of string will be converted to CF::String
|
66
|
+
# @param [CF::Base, String] key the key to access
|
67
|
+
# @return [CF::Base, nil]
|
68
|
+
|
69
|
+
def [](key)
|
70
|
+
key = CF::String.from_string(key) if key.is_a?(::String)
|
71
|
+
self.class.check_cftype(key)
|
72
|
+
raw = CF.CFDictionaryGetValue(self, key)
|
73
|
+
raw.null? ? nil : self.class.typecast(raw).retain.release_on_gc
|
74
|
+
end
|
75
|
+
|
76
|
+
# Sets the value associated with the key, or nil
|
77
|
+
# The key should be a CF::Base instance. As a convenience, instances of string will be converted to CF::String
|
78
|
+
# @param [CF::Base, String] key the key to access
|
79
|
+
# @param [CF::Base] value the value to set
|
80
|
+
# @return [CF::Base] the value that was set
|
81
|
+
def []=(key, value)
|
82
|
+
key = CF::String.from_string(key) if key.is_a?(::String)
|
83
|
+
self.class.check_cftype(key)
|
84
|
+
self.class.check_cftype(value)
|
85
|
+
CF.CFDictionarySetValue(self, key, value)
|
86
|
+
value
|
87
|
+
end
|
88
|
+
|
89
|
+
# Adds the key value pairs from the argument to self
|
90
|
+
#
|
91
|
+
# @param [CF::Dictionary] other
|
92
|
+
# @return self
|
93
|
+
def merge!(other)
|
94
|
+
other.each do |k,v|
|
95
|
+
self[k] = v
|
96
|
+
end
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns the number of key value pairs in the dictionary
|
101
|
+
# @return [Integer]
|
102
|
+
def length
|
103
|
+
CF.CFDictionaryGetCount(self)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns a ruby hash constructed by calling `to_ruby` on each key and value
|
107
|
+
#
|
108
|
+
# @return [Hash]
|
109
|
+
def to_ruby
|
110
|
+
Hash[collect {|k,v| [k.to_ruby, v.to_ruby]}]
|
111
|
+
end
|
112
|
+
alias_method :size, :length
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Rubyinteger
|
2
|
+
class Integer
|
3
|
+
# Converts the Integer to a {CF::Number} using {CF::Number.from_i}
|
4
|
+
# @return [CF::Number]
|
5
|
+
def to_cf
|
6
|
+
CF::Number.from_i(self)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Ruby float class
|
11
|
+
class Float
|
12
|
+
# Converts the Float to a {CF::Number} using {CF::Number.from_f}
|
13
|
+
# @return [CF::Number]
|
14
|
+
def to_cf
|
15
|
+
CF::Number.from_f(self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Ruby array class
|
20
|
+
class Array
|
21
|
+
# Converts the Array to an immutable {CF::Array} by calling `to_cf` on each element it contains
|
22
|
+
# @return [CF::Number]
|
23
|
+
def to_cf
|
24
|
+
CF::Array.immutable(collect(&:to_cf))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Ruby true class
|
29
|
+
class TrueClass
|
30
|
+
# Returns a CF::Boolean object representing true
|
31
|
+
# @return [CF::Boolean]
|
32
|
+
def to_cf
|
33
|
+
CF::Boolean::TRUE
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Ruby false class
|
38
|
+
class FalseClass
|
39
|
+
# Returns a CF::Boolean object representing false
|
40
|
+
# @return [CF::Boolean]
|
41
|
+
def to_cf
|
42
|
+
CF::Boolean::FALSE
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Ruby String class
|
47
|
+
class String
|
48
|
+
# Returns a {CF::String} or {CF::Data} representing the string.
|
49
|
+
# If the string has the encoding ASCII_8BIt a {CF::Data} is returned, if not a {CF::String} is returned
|
50
|
+
#
|
51
|
+
# @return [CF::String, CF::Data]
|
52
|
+
def to_cf
|
53
|
+
if encoding == Encoding::ASCII_8BIT
|
54
|
+
CF::Data.from_string self
|
55
|
+
else
|
56
|
+
CF::String.from_string self
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Ruby Time class
|
62
|
+
class Time
|
63
|
+
# Returns a {CF::Date} representing the time.
|
64
|
+
# @return [CF::Date]
|
65
|
+
def to_cf
|
66
|
+
CF::Date.from_time(self)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Ruby Hash class
|
71
|
+
class Hash
|
72
|
+
# Converts the Hash to an mutable {CF::Dictionary} by calling `to_cf` on each key and value it contains
|
73
|
+
# @return [CF::Dictionary]
|
74
|
+
def to_cf
|
75
|
+
CF::Dictionary.mutable.tap do |r|
|
76
|
+
each do |k,v|
|
77
|
+
r[k.to_cf] = v.to_cf
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module CF
|
2
|
+
typedef :pointer, :cfnumberref
|
3
|
+
enum :cf_number_type, [
|
4
|
+
:kCFNumberSInt8Type,1,
|
5
|
+
:kCFNumberSInt16Type,2,
|
6
|
+
:kCFNumberSInt32Type,3,
|
7
|
+
:kCFNumberSInt64Type,4,
|
8
|
+
:kCFNumberFloat32Type,5,
|
9
|
+
:kCFNumberFloat64Type,6,
|
10
|
+
:kCFNumberCharType,7,
|
11
|
+
:kCFNumberShortType,8,
|
12
|
+
:kCFNumberIntType,9,
|
13
|
+
:kCFNumberLongType,10,
|
14
|
+
:kCFNumberLongLongType,11,
|
15
|
+
:kCFNumberFloatType,12,
|
16
|
+
:kCFNumberDoubleType,13,
|
17
|
+
:kCFNumberCFIndexType,14,
|
18
|
+
:kCFNumberNSIntegerType,15,
|
19
|
+
:kCFNumberCGFloatType,16,
|
20
|
+
:kCFNumberMaxType,16
|
21
|
+
]
|
22
|
+
|
23
|
+
attach_function 'CFNumberGetValue', [:cfnumberref, :cf_number_type, :pointer], :uchar
|
24
|
+
attach_function 'CFNumberCreate', [:pointer, :cf_number_type, :pointer], :cfnumberref
|
25
|
+
attach_function 'CFNumberIsFloatType', [:pointer], :uchar
|
26
|
+
attach_function 'CFNumberCompare', [:cfnumberref, :cfnumberref, :pointer], :cfcomparisonresult
|
27
|
+
|
28
|
+
# Wrapper for CFNumberRef
|
29
|
+
#
|
30
|
+
#
|
31
|
+
class Number < Base
|
32
|
+
register_type 'CFNumber'
|
33
|
+
include Comparable
|
34
|
+
|
35
|
+
|
36
|
+
# Constructs a CF::Number from a float
|
37
|
+
# @param [Float] float
|
38
|
+
# @return [CF::Number]
|
39
|
+
def self.from_f(float)
|
40
|
+
p = FFI::MemoryPointer.new(:double)
|
41
|
+
p.write_double(float.to_f)
|
42
|
+
new(CF.CFNumberCreate(nil, :kCFNumberDoubleType, p)).release_on_gc
|
43
|
+
end
|
44
|
+
|
45
|
+
# Constructs a CF::Number from an integer
|
46
|
+
# @param [Integer] int
|
47
|
+
# @return [CF::Number]
|
48
|
+
def self.from_i(int)
|
49
|
+
p = FFI::MemoryPointer.new(:int64)
|
50
|
+
p.put_int64(0,int.to_i)
|
51
|
+
new(CF.CFNumberCreate(nil, :kCFNumberSInt64Type, p)).release_on_gc
|
52
|
+
end
|
53
|
+
|
54
|
+
# Compares the receiver with the argument
|
55
|
+
# @param [CF::Number] other
|
56
|
+
# @return [Integer]
|
57
|
+
def <=>(other)
|
58
|
+
raise TypeError, "argument should be CF::Number" unless other.is_a?(CF::Number)
|
59
|
+
CF.CFNumberCompare(self,other,nil)
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# Converts the CF::Number to either an Integer or a Float, depending on the result of CFNumberIsFloatType
|
64
|
+
#
|
65
|
+
# @return [Integer, Float]
|
66
|
+
def to_ruby
|
67
|
+
if CF.CFNumberIsFloatType(self) == 0
|
68
|
+
to_i
|
69
|
+
else
|
70
|
+
to_f
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Converts the CF::Number to an integer
|
75
|
+
# May raise if the conversion cannot be done without loss of precision
|
76
|
+
# @return [Integer]
|
77
|
+
def to_i
|
78
|
+
p = FFI::MemoryPointer.new(:int64)
|
79
|
+
if CF.CFNumberGetValue(self, :kCFNumberSInt64Type, p) != 0
|
80
|
+
p.get_int64 0
|
81
|
+
else
|
82
|
+
raise "CF.CFNumberGetValue failed to convert #{self.inspect} to kCFNumberSInt64Type"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Converts the CF::Number to a float
|
87
|
+
# May raise if the conversion cannot be done without loss of precision
|
88
|
+
# @return [Float]
|
89
|
+
def to_f
|
90
|
+
p = FFI::MemoryPointer.new(:double)
|
91
|
+
if CF.CFNumberGetValue(self, :kCFNumberDoubleType, p) != 0
|
92
|
+
p.read_double
|
93
|
+
else
|
94
|
+
raise "CF.CFNumberGetValue failed to convert #{self.inspect} to kCFNumberDoubleType"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module CF
|
2
|
+
typedef :pointer, :cfstringref
|
3
|
+
|
4
|
+
attach_function 'CFStringCreateWithBytes', [:pointer, :buffer_in, :cfindex, :uint, :char], :cfstringref
|
5
|
+
attach_function 'CFStringGetBytes', [:cfstringref, :uint], :pointer
|
6
|
+
attach_function 'CFStringGetMaximumSizeForEncoding', [:cfindex, :uint], :cfindex
|
7
|
+
attach_function 'CFStringGetLength', [:cfstringref], :cfindex
|
8
|
+
|
9
|
+
attach_function 'CFStringGetBytes', [:cfstringref, CF::Range.by_value, :uint, :uchar, :char, :buffer_out, :cfindex, :buffer_out], :cfindex
|
10
|
+
|
11
|
+
attach_function 'CFStringCompare', [:cfstringref, :cfstringref, :cfoptionflags], :cfcomparisonresult
|
12
|
+
|
13
|
+
# Wrapper class for CFString
|
14
|
+
#
|
15
|
+
# Unlike ruby, CFString is not an arbitrary bag of bytes - the data will be converted to a collection of unicode characters
|
16
|
+
class String < Base
|
17
|
+
include Comparable
|
18
|
+
register_type("CFString")
|
19
|
+
|
20
|
+
# The cfstring encoding for UTF8
|
21
|
+
UTF8 = 0x08000100 #From cfstring.h
|
22
|
+
|
23
|
+
|
24
|
+
# Creates a string from a ruby string
|
25
|
+
# The string must be convertable to UTF-8
|
26
|
+
#
|
27
|
+
# @param [String] s
|
28
|
+
# @return [CF::String]
|
29
|
+
def self.from_string(s)
|
30
|
+
s_utf = s.encode('UTF-8')
|
31
|
+
raw = CF.CFStringCreateWithBytes(nil, s_utf, s_utf.bytesize, UTF8, 0)
|
32
|
+
raw.null? ? nil : new(raw).release_on_gc
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the length, in unicode characters of the string
|
36
|
+
# @return [Integer]
|
37
|
+
def length
|
38
|
+
CF.CFStringGetLength(self)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Compares the receiver with the argument
|
42
|
+
# @param [CF::String] other
|
43
|
+
# @return [Integer]
|
44
|
+
def <=>(other)
|
45
|
+
Base.check_cftype(other)
|
46
|
+
CF.CFStringCompare(self,other,0)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Converts the CF::String to a UTF-8 ruby string
|
50
|
+
#
|
51
|
+
# @return [String]
|
52
|
+
def to_s
|
53
|
+
max_size = CF.CFStringGetMaximumSizeForEncoding(length, UTF8)
|
54
|
+
range = CF::Range.new
|
55
|
+
range[:location] = 0
|
56
|
+
range[:length] = length
|
57
|
+
buffer = FFI::MemoryPointer.new(:char, max_size)
|
58
|
+
|
59
|
+
cfindex = CF.find_type(:cfindex)
|
60
|
+
bytes_used_buffer = FFI::MemoryPointer.new(cfindex)
|
61
|
+
|
62
|
+
CF.CFStringGetBytes(self, range, UTF8, 0, 0, buffer, max_size, bytes_used_buffer)
|
63
|
+
|
64
|
+
bytes_used = if cfindex == CF.find_type(:long_long)
|
65
|
+
bytes_used_buffer.read_long_long
|
66
|
+
else
|
67
|
+
bytes_used_buffer.read_long
|
68
|
+
end
|
69
|
+
|
70
|
+
buffer.read_string(bytes_used).force_encoding(Encoding::UTF_8)
|
71
|
+
end
|
72
|
+
|
73
|
+
alias_method :to_ruby, :to_s
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
data/spec/array_spec.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CF::Array do
|
4
|
+
describe 'mutable' do
|
5
|
+
subject { CF::Array.mutable}
|
6
|
+
|
7
|
+
it { should be_a(CF::Array)}
|
8
|
+
it { should be_mutable}
|
9
|
+
|
10
|
+
describe '[]=' do
|
11
|
+
it 'should raise when trying to store a non cf value' do
|
12
|
+
expect {subject[0] = 123}.to raise_error(TypeError)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '<<' do
|
17
|
+
it 'should raise when trying to store a non cf value' do
|
18
|
+
expect {subject << 123}.to raise_error(TypeError)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'immutable' do
|
25
|
+
it 'should raise if all of the array elements are not cf values' do
|
26
|
+
expect {CF::Array.immutable([CF::Boolean::TRUE, 1])}.to raise_error(TypeError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return an immutable cfarray' do
|
30
|
+
CF::Array.immutable([CF::Boolean::TRUE]).should be_a(CF::Array)
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with an immutable array' do
|
34
|
+
subject { CF::Array.immutable([CF::Boolean::TRUE, CF::String.from_string('123')])}
|
35
|
+
|
36
|
+
describe '[]=' do
|
37
|
+
it 'should raise TypeError' do
|
38
|
+
expect {subject[0] = CF::Boolean::TRUE}.to raise_error(TypeError)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '<<' do
|
43
|
+
it 'should raise TypeError' do
|
44
|
+
expect {subject << CF::Boolean::TRUE}.to raise_error(TypeError)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "with an array" do
|
51
|
+
subject { CF::Array.immutable([CF::Boolean::TRUE, CF::String.from_string('123')])}
|
52
|
+
|
53
|
+
describe '[]' do
|
54
|
+
it 'should return the typecast value at the index' do
|
55
|
+
subject[1].should be_a(CF::String)
|
56
|
+
subject[1].should == CF::String.from_string('123')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
describe 'length' do
|
62
|
+
it 'should return the count of items in the dictionary' do
|
63
|
+
subject.length.should == 2
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'to_ruby' do
|
68
|
+
it 'should return the result of calling to ruby on its contents' do
|
69
|
+
subject.to_ruby.should == [true, '123']
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'each' do
|
74
|
+
it 'should iterate over each value' do
|
75
|
+
values = []
|
76
|
+
subject.each do |v|
|
77
|
+
values << v
|
78
|
+
end
|
79
|
+
values[0].should == CF::Boolean::TRUE
|
80
|
+
values[1].should == CF::String.from_string('123')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should be enumerable' do
|
85
|
+
values = {}
|
86
|
+
subject.each_with_index do |value, index|
|
87
|
+
values[index] = value
|
88
|
+
end
|
89
|
+
values.should == {0 => CF::Boolean::TRUE, 1 => CF::String.from_string('123')}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|