corefoundation 0.2.0 → 0.3.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.
- 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
|