corefoundation 0.2.0 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/corefoundation/array.rb +4 -5
- data/lib/corefoundation/base.rb +39 -143
- data/lib/corefoundation/data.rb +2 -6
- data/lib/corefoundation/date.rb +1 -1
- data/lib/corefoundation/dictionary.rb +3 -4
- data/lib/corefoundation/exceptions.rb +16 -0
- data/lib/corefoundation/memory.rb +47 -0
- data/lib/corefoundation/number.rb +2 -2
- data/lib/corefoundation/preferences.rb +134 -0
- data/lib/corefoundation/range.rb +10 -0
- data/lib/corefoundation/refinements.rb +121 -0
- data/lib/corefoundation/register.rb +24 -0
- data/lib/corefoundation/string.rb +6 -29
- data/lib/corefoundation/version.rb +1 -1
- data/lib/corefoundation.rb +38 -13
- metadata +72 -121
- data/CHANGELOG +0 -12
- data/README.md +0 -40
- data/lib/corefoundation/extensions.rb +0 -158
- data/spec/array_spec.rb +0 -92
- data/spec/boolean_spec.rb +0 -24
- data/spec/data_spec.rb +0 -30
- data/spec/date_spec.rb +0 -25
- data/spec/dictionary_spec.rb +0 -81
- data/spec/extensions_spec.rb +0 -127
- data/spec/null_spec.rb +0 -7
- data/spec/number_spec.rb +0 -52
- data/spec/spec_helper.rb +0 -10
- data/spec/string_spec.rb +0 -48
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0643a8f8fa6e54707a3f01f8ee355d087dbd5c489a5421ce71ff99fb56efe02f
|
4
|
+
data.tar.gz: '0168e360dc7c45ea8523198fffd2b133d4de7965f764063a3806caa9ccd37cfb'
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 72c31cff02be17a7864bdc57bc77c3cb8af9becad10fa33f0358d9b1765fb3edafce7de53ebfc9fc61c8e9125bca5e0f70e7b20674ad52c555bbeddae1d6c0a3
|
7
|
+
data.tar.gz: f70c46f8d528a0783486f0ab7615332bfe52d4fbe841171aefa289fb48675e92bfa48b3c8b164b5d49227bd55f7f8b170059d78dd696242939fe074f39bef9c9
|
data/lib/corefoundation/array.rb
CHANGED
@@ -49,7 +49,7 @@ module CF
|
|
49
49
|
range[:location] = 0
|
50
50
|
range[:length] = length
|
51
51
|
callback = lambda do |value, _|
|
52
|
-
yield Base.typecast(value).retain
|
52
|
+
yield Base.typecast(value).retain
|
53
53
|
end
|
54
54
|
CF.CFArrayApplyFunction(self, range, callback, nil)
|
55
55
|
self
|
@@ -64,13 +64,13 @@ module CF
|
|
64
64
|
end
|
65
65
|
m = FFI::MemoryPointer.new(:pointer, array.length)
|
66
66
|
m.write_array_of_pointer(array)
|
67
|
-
new(CF.CFArrayCreate(nil,m,array.length,CF::kCFTypeArrayCallBacks.to_ptr))
|
67
|
+
new(CF.CFArrayCreate(nil,m,array.length,CF::kCFTypeArrayCallBacks.to_ptr))
|
68
68
|
end
|
69
69
|
|
70
70
|
# Creates a new, empty mutable CFArray
|
71
71
|
# @return [CF::Array] A mutable CF::Array containing the objects, setup to release the array upon garbage collection
|
72
72
|
def self.mutable
|
73
|
-
result = new(CF.CFArrayCreateMutable nil, 0, CF::kCFTypeArrayCallBacks.to_ptr)
|
73
|
+
result = new(CF.CFArrayCreateMutable nil, 0, CF::kCFTypeArrayCallBacks.to_ptr)
|
74
74
|
result.instance_variable_set(:@mutable, true)
|
75
75
|
result
|
76
76
|
end
|
@@ -79,7 +79,7 @@ module CF
|
|
79
79
|
# @param [Integer] index the 0 based index of the item to retrieve. Behaviour is undefined if it is not in the range 0...size
|
80
80
|
# @return [CF::Base] a subclass of CF::Base
|
81
81
|
def [](index)
|
82
|
-
Base.typecast(CF.CFArrayGetValueAtIndex(self, index)).retain
|
82
|
+
Base.typecast(CF.CFArrayGetValueAtIndex(self, index)).retain
|
83
83
|
end
|
84
84
|
|
85
85
|
# Sets object at the index
|
@@ -92,7 +92,6 @@ module CF
|
|
92
92
|
raise TypeError, "instance is not mutable" unless mutable?
|
93
93
|
self.class.check_cftype(value)
|
94
94
|
CF.CFArraySetValueAtIndex(self, index, value)
|
95
|
-
value
|
96
95
|
end
|
97
96
|
|
98
97
|
# Appends a value to the array
|
data/lib/corefoundation/base.rb
CHANGED
@@ -1,101 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
# The top level namespace for the corefoundation library. The raw FFI generated methods are attached here
|
3
|
-
#
|
4
|
-
#
|
5
4
|
module CF
|
6
|
-
|
7
|
-
|
5
|
+
# The base class for all of the wrapper classes in CF module.
|
6
|
+
class Base
|
7
|
+
using CF::Refinements
|
8
8
|
|
9
|
-
if FFI::Platform::ARCH == 'x86_64'
|
10
|
-
typedef :long_long, :cfindex
|
11
|
-
typedef :long_long, :cfcomparisonresult
|
12
|
-
typedef :ulong_long, :cfoptionflags
|
13
|
-
typedef :ulong_long, :cftypeid
|
14
|
-
typedef :ulong_long, :cfhashcode
|
15
|
-
else
|
16
|
-
typedef :long, :cfindex
|
17
|
-
typedef :long, :cfcomparisonresult
|
18
|
-
typedef :ulong, :cfoptionflags
|
19
|
-
typedef :ulong, :cftypeid
|
20
|
-
typedef :ulong, :cfhashcode
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
# @private
|
25
|
-
class Range < FFI::Struct
|
26
|
-
layout :location, :cfindex,
|
27
|
-
:length, :cfindex
|
28
|
-
end
|
29
|
-
|
30
|
-
typedef :pointer, :cftyperef
|
31
|
-
|
32
|
-
#general utility functions
|
33
|
-
attach_function :show, 'CFShow', [:cftyperef], :void
|
34
|
-
attach_function :release, 'CFRelease', [:cftyperef], :void
|
35
|
-
attach_function :retain, 'CFRetain', [:cftyperef], :cftyperef
|
36
|
-
attach_function 'CFEqual', [:cftyperef, :cftyperef], :char
|
37
|
-
attach_function 'CFHash', [:cftyperef], :cfhashcode
|
38
|
-
attach_function 'CFCopyDescription', [:cftyperef], :cftyperef
|
39
|
-
attach_function 'CFGetTypeID', [:cftyperef], :cftypeid
|
40
|
-
|
41
|
-
# The base class for all of the wrapper classes
|
42
|
-
#
|
43
|
-
# @abstract
|
44
|
-
class Base
|
45
9
|
@@type_map = {}
|
10
|
+
include CF::Register
|
11
|
+
include CF::Memory
|
46
12
|
|
47
|
-
|
48
|
-
class Releaser
|
49
|
-
def initialize(ptr)
|
50
|
-
@address = ptr.address
|
51
|
-
end
|
13
|
+
attr_reader :ptr
|
52
14
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
15
|
+
# Raises an exception if the argument does not inherit from CF::Base
|
16
|
+
#
|
17
|
+
# @param cftyperef object to check
|
18
|
+
def self.check_cftype(cftyperef)
|
19
|
+
raise TypeError, "#{cftyperef.inspect} is not a cftype" unless cftyperef.is_a?(CF::Base)
|
59
20
|
end
|
60
21
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
# If the pointer is not a CFTypeRef behaviour is undefined
|
71
|
-
# @param [FFI::Pointer] cftyperef Object to wrap
|
72
|
-
# @return A wrapper object inheriting from CF::Base
|
73
|
-
def typecast(cftyperef)
|
74
|
-
klass = klass_from_cf_type cftyperef
|
75
|
-
klass.new(cftyperef)
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
def klass_from_cf_type cftyperef
|
80
|
-
klass = @@type_map[CF.CFGetTypeID(cftyperef)]
|
81
|
-
if !klass
|
82
|
-
raise TypeError, "No class registered for cf type #{cftyperef.inspect}"
|
83
|
-
end
|
84
|
-
klass
|
85
|
-
end
|
86
|
-
|
87
|
-
def register_type(type_name)
|
88
|
-
CF.attach_function "#{type_name}GetTypeID", [], :cftypeid
|
89
|
-
@@type_map[CF.send("#{type_name}GetTypeID")] = self
|
90
|
-
end
|
22
|
+
# Wraps an FFI::Pointer with the appropriate subclass of CF::Base
|
23
|
+
# If the pointer is not a CFTypeRef behaviour is undefined
|
24
|
+
#
|
25
|
+
# @param [FFI::Pointer] cftyperef Object to wrap
|
26
|
+
# @return A wrapper object inheriting from CF::Base
|
27
|
+
def self.typecast(cftyperef)
|
28
|
+
klass = klass_from_cf_type cftyperef
|
29
|
+
klass.new(cftyperef)
|
30
|
+
end
|
91
31
|
|
32
|
+
# @param [FFI::Pointer] pointer The pointer to wrap
|
33
|
+
def initialize(pointer)
|
34
|
+
@ptr = FFI::Pointer.new(pointer)
|
35
|
+
ObjectSpace.define_finalizer(self, self.class.finalize(ptr))
|
92
36
|
end
|
93
37
|
|
94
|
-
#
|
95
|
-
|
96
|
-
|
97
|
-
def initialize(ptr)
|
98
|
-
@ptr = FFI::Pointer.new(ptr)
|
38
|
+
# @param [FFI::Pointer] pointer to the address of the object
|
39
|
+
def self.finalize(pointer)
|
40
|
+
proc { CF.release(pointer) unless pointer.address.zero }
|
99
41
|
end
|
100
42
|
|
101
43
|
# Whether the instance is the CFNull singleton
|
@@ -105,49 +47,6 @@ module CF
|
|
105
47
|
equals?(CF::NULL)
|
106
48
|
end
|
107
49
|
|
108
|
-
# Returns the wrapped pointer
|
109
|
-
# @return [FFI::Pointer]
|
110
|
-
def to_ptr
|
111
|
-
@ptr
|
112
|
-
end
|
113
|
-
|
114
|
-
# Sets the wrapper pointer. You should only do this rarely. If you have used release_on_gc then that
|
115
|
-
# finalizer will still be called on the original pointer value
|
116
|
-
#
|
117
|
-
def ptr= ptr
|
118
|
-
@ptr = ptr
|
119
|
-
end
|
120
|
-
|
121
|
-
# Calls CFRetain on the wrapped pointer
|
122
|
-
# @return Returns self
|
123
|
-
def retain
|
124
|
-
CF.retain(self)
|
125
|
-
self
|
126
|
-
end
|
127
|
-
|
128
|
-
# Calls CFRelease on the wrapped pointer
|
129
|
-
# @return Returns self
|
130
|
-
def release
|
131
|
-
CF.release(self)
|
132
|
-
self
|
133
|
-
end
|
134
|
-
|
135
|
-
# Installs a finalizer on the wrapper object that will cause it to call CFRelease on the pointer
|
136
|
-
# when the wrapper is garbage collected
|
137
|
-
# @return Returns self
|
138
|
-
def release_on_gc
|
139
|
-
ObjectSpace.define_finalizer(@ptr, Releaser.new(@ptr))
|
140
|
-
self
|
141
|
-
end
|
142
|
-
|
143
|
-
# Returns a ruby string containing the output of CFCopyDescription for the wrapped object
|
144
|
-
#
|
145
|
-
# @return [String]
|
146
|
-
def inspect
|
147
|
-
cf = CF::String.new(CF.CFCopyDescription(self))
|
148
|
-
cf.to_s.tap {cf.release}
|
149
|
-
end
|
150
|
-
|
151
50
|
# Uses CFHash to return a hash code
|
152
51
|
#
|
153
52
|
# @return [Integer]
|
@@ -156,8 +55,6 @@ module CF
|
|
156
55
|
end
|
157
56
|
|
158
57
|
# eql? (and ==) are implemented using CFEqual
|
159
|
-
#
|
160
|
-
#
|
161
58
|
def eql?(other)
|
162
59
|
if other.is_a?(CF::Base)
|
163
60
|
CF.CFEqual(self, other) != 0
|
@@ -165,10 +62,10 @@ module CF
|
|
165
62
|
false
|
166
63
|
end
|
167
64
|
end
|
168
|
-
|
65
|
+
|
66
|
+
alias == :eql?
|
67
|
+
|
169
68
|
# equals? is defined as returning true if the wrapped pointer is the same
|
170
|
-
#
|
171
|
-
#
|
172
69
|
def equals?(other)
|
173
70
|
if other.is_a?(CF::Base)
|
174
71
|
@ptr.address == other.to_ptr.address
|
@@ -176,22 +73,21 @@ module CF
|
|
176
73
|
false
|
177
74
|
end
|
178
75
|
end
|
179
|
-
|
180
|
-
alias_method :==, :eql?
|
181
76
|
|
182
|
-
# Converts the CF object into a ruby object. Subclasses typically override this to return
|
183
|
-
# an appropriate object (for example CF::String returns a String)
|
184
|
-
#
|
185
77
|
def to_ruby
|
186
|
-
self
|
78
|
+
raise CF::Exceptions::MethodNotImplemented, "#{self.class} should implement the to_ruby method."
|
187
79
|
end
|
188
80
|
|
189
|
-
#
|
190
|
-
#
|
81
|
+
# This is a no-op on CF::Base and its subclasses. Always returns self.
|
191
82
|
#
|
83
|
+
# @return Returns self
|
192
84
|
def to_cf
|
193
85
|
self
|
194
86
|
end
|
195
|
-
end
|
196
87
|
|
88
|
+
private
|
89
|
+
def self.type_map
|
90
|
+
@@type_map
|
91
|
+
end
|
92
|
+
end
|
197
93
|
end
|
data/lib/corefoundation/data.rb
CHANGED
@@ -15,7 +15,7 @@ module CF
|
|
15
15
|
# @param [String] s the string to use
|
16
16
|
# @return [CF::Data]
|
17
17
|
def self.from_string(s)
|
18
|
-
new(CF.CFDataCreate(nil, s, s.bytesize))
|
18
|
+
new(CF.CFDataCreate(nil, s, s.bytesize))
|
19
19
|
end
|
20
20
|
|
21
21
|
# Creates a ruby string from the wrapped data. The encoding will always be ASCII_8BIT
|
@@ -23,11 +23,7 @@ module CF
|
|
23
23
|
# @return [String]
|
24
24
|
def to_s
|
25
25
|
ptr = CF.CFDataGetBytePtr(self)
|
26
|
-
|
27
|
-
ptr.read_string(CF.CFDataGetLength(self)).force_encoding(Encoding::ASCII_8BIT)
|
28
|
-
else
|
29
|
-
ptr.read_string(CF.CFDataGetLength(self))
|
30
|
-
end
|
26
|
+
ptr.read_string(CF.CFDataGetLength(self)).force_encoding(Encoding::ASCII_8BIT)
|
31
27
|
end
|
32
28
|
|
33
29
|
# The size in bytes of the CFData
|
data/lib/corefoundation/date.rb
CHANGED
@@ -17,7 +17,7 @@ module CF
|
|
17
17
|
# @param [Time] time
|
18
18
|
# @return [CF::Date] a CF::Date instance that will be released on garbage collection
|
19
19
|
def self.from_time(time)
|
20
|
-
new(CF.CFDateCreate(nil, time.to_f - CF.kCFAbsoluteTimeIntervalSince1970))
|
20
|
+
new(CF.CFDateCreate(nil, time.to_f - CF.kCFAbsoluteTimeIntervalSince1970))
|
21
21
|
end
|
22
22
|
|
23
23
|
# returns a ruby Time instance corresponding to the same point in time
|
@@ -46,7 +46,7 @@ module CF
|
|
46
46
|
#
|
47
47
|
# @return [CF::Dictionary]
|
48
48
|
def self.mutable
|
49
|
-
new(CF.CFDictionaryCreateMutable nil, 0, CF.kCFTypeDictionaryKeyCallBacks.to_ptr, CF.kCFTypeDictionaryValueCallBacks.to_ptr)
|
49
|
+
new(CF.CFDictionaryCreateMutable nil, 0, CF.kCFTypeDictionaryKeyCallBacks.to_ptr, CF.kCFTypeDictionaryValueCallBacks.to_ptr)
|
50
50
|
end
|
51
51
|
|
52
52
|
# Iterates over the array yielding the value to the block
|
@@ -55,7 +55,7 @@ module CF
|
|
55
55
|
|
56
56
|
def each
|
57
57
|
callback = lambda do |key, value, _|
|
58
|
-
yield [Base.typecast(key).retain
|
58
|
+
yield [Base.typecast(key).retain, Base.typecast(value).retain]
|
59
59
|
end
|
60
60
|
CF.CFDictionaryApplyFunction(self, callback, nil)
|
61
61
|
self
|
@@ -70,7 +70,7 @@ module CF
|
|
70
70
|
key = CF::String.from_string(key) if key.is_a?(::String)
|
71
71
|
self.class.check_cftype(key)
|
72
72
|
raw = CF.CFDictionaryGetValue(self, key)
|
73
|
-
raw.null? ? nil : self.class.typecast(raw).retain
|
73
|
+
raw.null? ? nil : self.class.typecast(raw).retain
|
74
74
|
end
|
75
75
|
|
76
76
|
# Sets the value associated with the key, or nil
|
@@ -83,7 +83,6 @@ module CF
|
|
83
83
|
self.class.check_cftype(key)
|
84
84
|
self.class.check_cftype(value)
|
85
85
|
CF.CFDictionarySetValue(self, key, value)
|
86
|
-
value
|
87
86
|
end
|
88
87
|
|
89
88
|
# Adds the key value pairs from the argument to self
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module CF
|
2
|
+
module Exceptions
|
3
|
+
# Raised when the preference value couldn't be found for a domain.
|
4
|
+
class PreferenceDoesNotExist < StandardError
|
5
|
+
def initialize(key, domain, hostname = nil)
|
6
|
+
super("Returned NULL value for \"#{key}\" in \"#{domain}\"#{", hostname: #{hostname}" if hostname}")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
# Raised when the preference value failed to write.
|
10
|
+
class PreferenceSyncFailed < StandardError
|
11
|
+
def initialize(key, domain, hostname = nil)
|
12
|
+
super("Couldn't write preference value for \"#{key}\" in \"#{domain}\"#{", hostname: #{hostname}" if hostname}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The top level namespace for the corefoundation library. The raw FFI generated methods are attached here
|
4
|
+
module CF
|
5
|
+
attach_function :show, 'CFShow', [:cftyperef], :void
|
6
|
+
attach_function :release, 'CFRelease', [:cftyperef], :void
|
7
|
+
attach_function :retain, 'CFRetain', [:cftyperef], :cftyperef
|
8
|
+
attach_function 'CFEqual', [:cftyperef, :cftyperef], :char
|
9
|
+
attach_function 'CFHash', [:cftyperef], :cfhashcode
|
10
|
+
attach_function 'CFCopyDescription', [:cftyperef], :cftyperef
|
11
|
+
attach_function 'CFGetTypeID', [:cftyperef], :cftypeid
|
12
|
+
|
13
|
+
# Provides a more declarative way to define all required abstract methods.
|
14
|
+
# This gets included in the CF::Base class whose subclasses then need to define those methods.
|
15
|
+
module Memory
|
16
|
+
|
17
|
+
# Returns a ruby string containing the output of CFCopyDescription for the wrapped object
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
def inspect
|
21
|
+
CF::String.new(CF.CFCopyDescription(self)).to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
# Calls CFRelease on the wrapped pointer
|
25
|
+
#
|
26
|
+
# @return Returns self
|
27
|
+
def release
|
28
|
+
CF.release(self)
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# Calls CFRetain on the wrapped pointer
|
33
|
+
#
|
34
|
+
# @return Returns self
|
35
|
+
def retain
|
36
|
+
CF.retain(self)
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the wrapped pointer
|
41
|
+
#
|
42
|
+
# @return [FFI::Pointer]
|
43
|
+
def to_ptr
|
44
|
+
ptr
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -39,7 +39,7 @@ module CF
|
|
39
39
|
def self.from_f(float)
|
40
40
|
p = FFI::MemoryPointer.new(:double)
|
41
41
|
p.write_double(float.to_f)
|
42
|
-
new(CF.CFNumberCreate(nil, :kCFNumberDoubleType, p))
|
42
|
+
new(CF.CFNumberCreate(nil, :kCFNumberDoubleType, p))
|
43
43
|
end
|
44
44
|
|
45
45
|
# Constructs a CF::Number from an integer
|
@@ -48,7 +48,7 @@ module CF
|
|
48
48
|
def self.from_i(int)
|
49
49
|
p = FFI::MemoryPointer.new(:int64)
|
50
50
|
p.put_int64(0,int.to_i)
|
51
|
-
new(CF.CFNumberCreate(nil, :kCFNumberSInt64Type, p))
|
51
|
+
new(CF.CFNumberCreate(nil, :kCFNumberSInt64Type, p))
|
52
52
|
end
|
53
53
|
|
54
54
|
# Compares the receiver with the argument
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module CF
|
2
|
+
typedef :pointer, :cfpropertylistref
|
3
|
+
typedef :cfstringref, :key
|
4
|
+
typedef :cfstringref, :application_id
|
5
|
+
typedef :cfstringref, :username
|
6
|
+
typedef :cfstringref, :hostname
|
7
|
+
typedef :cfpropertylistref, :value
|
8
|
+
|
9
|
+
attach_variable 'kCFPreferencesCurrentUser', :cfstringref
|
10
|
+
attach_variable 'kCFPreferencesAnyUser', :cfstringref
|
11
|
+
attach_variable 'kCFPreferencesCurrentHost', :cfstringref
|
12
|
+
attach_variable 'kCFPreferencesAnyHost', :cfstringref
|
13
|
+
|
14
|
+
attach_function 'CFPreferencesCopyAppValue', [:key, :application_id], :cfpropertylistref
|
15
|
+
attach_function 'CFPreferencesCopyValue', [:key, :application_id, :username, :hostname], :cfpropertylistref
|
16
|
+
|
17
|
+
attach_function 'CFPreferencesSetAppValue', [:key, :value, :application_id], :void
|
18
|
+
attach_function 'CFPreferencesSetValue', [:key, :value, :application_id, :username, :hostname], :void
|
19
|
+
|
20
|
+
attach_function 'CFPreferencesAppSynchronize', [:application_id], :bool
|
21
|
+
|
22
|
+
# Interface to the preference utilities from Corefoundation.framework.
|
23
|
+
# Documentation at https://developer.apple.com/documentation/corefoundation/preferences_utilities
|
24
|
+
#
|
25
|
+
class Preferences
|
26
|
+
using CF::Refinements
|
27
|
+
|
28
|
+
CURRENT_USER = CF.kCFPreferencesCurrentUser
|
29
|
+
ALL_USERS = CF.kCFPreferencesAnyUser
|
30
|
+
CURRENT_HOST = CF.kCFPreferencesCurrentHost
|
31
|
+
ALL_HOSTS = CF.kCFPreferencesAnyHost
|
32
|
+
|
33
|
+
class << self
|
34
|
+
# Returns the output from `CFPreferencesCopyValue` call after converting it to ruby type.
|
35
|
+
#
|
36
|
+
# @param [String] key Preference key to read
|
37
|
+
# @param [String] application_id Preference domain for the key
|
38
|
+
# @param [String, Symbol] username Domain user (current, any or a specific user)
|
39
|
+
# @param [String, Symbol] hostname Hostname (current, all hosts or a specific host)
|
40
|
+
#
|
41
|
+
# @return [VALUE] Preference value returned from the `CFPreferencesCopyValue` call.
|
42
|
+
#
|
43
|
+
def get(key, application_id, username = nil, hostname = nil)
|
44
|
+
plist_ref = if username && hostname
|
45
|
+
CF.CFPreferencesCopyValue(
|
46
|
+
key.to_cf,
|
47
|
+
application_id.to_cf,
|
48
|
+
arg_to_cf(username),
|
49
|
+
arg_to_cf(hostname)
|
50
|
+
)
|
51
|
+
else
|
52
|
+
CF.CFPreferencesCopyAppValue(key.to_cf, application_id.to_cf)
|
53
|
+
end
|
54
|
+
CF::Base.typecast(plist_ref).to_ruby unless plist_ref.null?
|
55
|
+
end
|
56
|
+
|
57
|
+
# Calls the {#self.get} method and raise a `PreferenceDoesNotExist` error if `nil` is returned.
|
58
|
+
#
|
59
|
+
# @param [String] key Preference key to read
|
60
|
+
# @param [String] application_id Preference domain for the key
|
61
|
+
# @param [String, Symbol] username Domain user (current, any or a specific user)
|
62
|
+
# @param [String, Symbol] hostname Hostname (current, all hosts or a specific host)
|
63
|
+
#
|
64
|
+
# @raise [PreferenceDoesNotExist] If returned value is nil.
|
65
|
+
#
|
66
|
+
# @return [VALUE] Preference value returned from the {#self.get} method call.
|
67
|
+
#
|
68
|
+
def get!(key, application_id, username = nil, hostname = nil)
|
69
|
+
value = get(key, application_id, username, hostname)
|
70
|
+
if value.nil?
|
71
|
+
raise(CF::Exceptions::PreferenceDoesNotExist.new(key, application_id, hostname))
|
72
|
+
else
|
73
|
+
value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Set the value for preference domain using `CFPreferencesSetValue`.
|
78
|
+
#
|
79
|
+
# @param [String] key Preference key
|
80
|
+
# @param [Integer, Float, String, TrueClass, FalseClass, Hash, Array] value Preference value
|
81
|
+
# @param [String] application_id Preference domain
|
82
|
+
# @param [String, Symbol] username Domain user (current, any or a specific user)
|
83
|
+
# @param [String, Symbol] hostname Hostname (current, all hosts or a specific host)
|
84
|
+
#
|
85
|
+
# @return [TrueClass, FalseClass] Returns true if preference was successfully written to storage, otherwise false.
|
86
|
+
#
|
87
|
+
def set(key, value, application_id, username = nil, hostname = nil)
|
88
|
+
if username && hostname
|
89
|
+
CF.CFPreferencesSetValue(
|
90
|
+
key.to_cf,
|
91
|
+
arg_to_cf(value),
|
92
|
+
application_id.to_cf,
|
93
|
+
arg_to_cf(username),
|
94
|
+
arg_to_cf(hostname)
|
95
|
+
)
|
96
|
+
else
|
97
|
+
CF.CFPreferencesSetAppValue(
|
98
|
+
key.to_cf,
|
99
|
+
arg_to_cf(value),
|
100
|
+
application_id.to_cf
|
101
|
+
)
|
102
|
+
end
|
103
|
+
CF.CFPreferencesAppSynchronize(application_id.to_cf)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Calls the {#self.set} method and raise a `PreferenceSyncFailed` error if `false` is returned.
|
107
|
+
#
|
108
|
+
# @param [String] key Preference key to write
|
109
|
+
# @param [String] application_id Preference domain for the key
|
110
|
+
# @param [String, Symbol] username Domain user (current, any or a specific user)
|
111
|
+
# @param [String, Symbol] hostname Hostname (current, all hosts or a specific host)
|
112
|
+
#
|
113
|
+
# @raise [PreferenceSyncFailed] If {#self.set} call returned false.
|
114
|
+
#
|
115
|
+
# @return [VALUE] Returns nil if preference value is successfully written.
|
116
|
+
#
|
117
|
+
def set!(key, value, application_id, username = nil, hostname = nil)
|
118
|
+
raise(CF::Exceptions::PreferenceSyncFailed.new(key, application_id, hostname)) unless set(key, value, application_id, username, hostname)
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
# Convert an object from ruby to cf type.
|
123
|
+
#
|
124
|
+
# @param [VALUE, CFType] arg A ruby or corefoundation object.
|
125
|
+
#
|
126
|
+
# @return [CFType] A wrapped CF object.
|
127
|
+
#
|
128
|
+
# @visiblity private
|
129
|
+
def arg_to_cf(arg)
|
130
|
+
arg.respond_to?(:to_cf) ? arg.to_cf : arg
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|