corefoundation 0.1.4 → 0.3.13
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 +40 -143
- data/lib/corefoundation/data.rb +1 -1
- 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 -15
- data/lib/corefoundation/version.rb +1 -1
- data/lib/corefoundation.rb +38 -11
- metadata +41 -58
- data/README.md +0 -39
- data/lib/corefoundation/extensions.rb +0 -81
- data/spec/array_spec.rb +0 -92
- data/spec/boolean_spec.rb +0 -24
- data/spec/data_spec.rb +0 -26
- data/spec/date_spec.rb +0 -25
- data/spec/dictionary_spec.rb +0 -81
- data/spec/extensions_spec.rb +0 -63
- 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 -39
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b4052eded27a6188c93ee482a6d7dfa3d3bf5bcdacbbe9a9801ad1dd86c28790
|
4
|
+
data.tar.gz: 2d6dab3b3d788a0671acfd36781739d763014db6c3a864ea64437ed12719e5bc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: '09ed7185a6cd6046bed44eef079013b5b15a5df17d70c01ac13aa17dcbcae01df39afb5868e40d70409cdd46136cdc2e92d829503a05341ef2b609f5e29cf84a'
|
7
|
+
data.tar.gz: c62e84155e57619823cccc52b9b6ff34cef39d2e657500505bb72b192da809bab178127c70040b6b284dd138bb02377a461d2de65925775d65bc576b87ca7753
|
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)
|
52
|
+
yield Base.typecast(value)
|
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))
|
82
|
+
Base.typecast(CF.CFArrayGetValueAtIndex(self, index))
|
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,44 @@
|
|
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))
|
36
|
+
CF.retain(ptr)
|
92
37
|
end
|
93
38
|
|
94
|
-
#
|
95
|
-
|
96
|
-
|
97
|
-
def initialize(ptr)
|
98
|
-
@ptr = FFI::Pointer.new(ptr)
|
39
|
+
# @param [FFI::Pointer] pointer to the address of the object
|
40
|
+
def self.finalize(pointer)
|
41
|
+
proc { CF.release(pointer) unless pointer.address.zero? }
|
99
42
|
end
|
100
43
|
|
101
44
|
# Whether the instance is the CFNull singleton
|
@@ -105,49 +48,6 @@ module CF
|
|
105
48
|
equals?(CF::NULL)
|
106
49
|
end
|
107
50
|
|
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
51
|
# Uses CFHash to return a hash code
|
152
52
|
#
|
153
53
|
# @return [Integer]
|
@@ -156,8 +56,6 @@ module CF
|
|
156
56
|
end
|
157
57
|
|
158
58
|
# eql? (and ==) are implemented using CFEqual
|
159
|
-
#
|
160
|
-
#
|
161
59
|
def eql?(other)
|
162
60
|
if other.is_a?(CF::Base)
|
163
61
|
CF.CFEqual(self, other) != 0
|
@@ -165,10 +63,10 @@ module CF
|
|
165
63
|
false
|
166
64
|
end
|
167
65
|
end
|
168
|
-
|
66
|
+
|
67
|
+
alias == :eql?
|
68
|
+
|
169
69
|
# equals? is defined as returning true if the wrapped pointer is the same
|
170
|
-
#
|
171
|
-
#
|
172
70
|
def equals?(other)
|
173
71
|
if other.is_a?(CF::Base)
|
174
72
|
@ptr.address == other.to_ptr.address
|
@@ -176,22 +74,21 @@ module CF
|
|
176
74
|
false
|
177
75
|
end
|
178
76
|
end
|
179
|
-
|
180
|
-
alias_method :==, :eql?
|
181
77
|
|
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
78
|
def to_ruby
|
186
|
-
self
|
79
|
+
raise CF::Exceptions::MethodNotImplemented, "#{self.class} should implement the to_ruby method."
|
187
80
|
end
|
188
81
|
|
189
|
-
#
|
190
|
-
#
|
82
|
+
# This is a no-op on CF::Base and its subclasses. Always returns self.
|
191
83
|
#
|
84
|
+
# @return Returns self
|
192
85
|
def to_cf
|
193
86
|
self
|
194
87
|
end
|
195
|
-
end
|
196
88
|
|
89
|
+
private
|
90
|
+
def self.type_map
|
91
|
+
@@type_map
|
92
|
+
end
|
93
|
+
end
|
197
94
|
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
|
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)
|
58
|
+
yield [Base.typecast(key), Base.typecast(value)]
|
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)
|
73
|
+
raw.null? ? nil : self.class.typecast(raw)
|
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
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CF
|
4
|
+
module Refinements
|
5
|
+
# Patches for ruby Integer
|
6
|
+
refine Integer do
|
7
|
+
# Converts the Integer to a {CF::Number} using {CF::Number.from_i}
|
8
|
+
# @return [CF::Number]
|
9
|
+
def to_cf
|
10
|
+
CF::Number.from_i(self)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Patches for ruby Float
|
15
|
+
refine Float do
|
16
|
+
# Converts the Float to a {CF::Number} using {CF::Number.from_f}
|
17
|
+
# @return [CF::Number]
|
18
|
+
def to_cf
|
19
|
+
CF::Number.from_f(self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Patches for ruby Array
|
24
|
+
refine Array do
|
25
|
+
# Converts the Array to an immutable {CF::Array} by calling `to_cf` on each element it contains
|
26
|
+
# @return [CF::Number]
|
27
|
+
def to_cf
|
28
|
+
CF::Array.immutable(collect(&:to_cf))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Patches for ruby TrueClass
|
33
|
+
refine TrueClass do
|
34
|
+
# Returns a CF::Boolean object representing true
|
35
|
+
# @return [CF::Boolean]
|
36
|
+
def to_cf
|
37
|
+
CF::Boolean::TRUE
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Patches for ruby FalseClass
|
42
|
+
refine FalseClass do
|
43
|
+
# Returns a CF::Boolean object representing false
|
44
|
+
# @return [CF::Boolean]
|
45
|
+
def to_cf
|
46
|
+
CF::Boolean::FALSE
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Patches for ruby String
|
51
|
+
refine String do
|
52
|
+
# Returns a {CF::String} or {CF::Data} representing the string.
|
53
|
+
# If {#binary?} returns true a {CF::Data} is returned, if not a {CF::String} is returned
|
54
|
+
#
|
55
|
+
# If you want a {CF::Data} with the contents of a non binary string, use {#to_cf_data}
|
56
|
+
#
|
57
|
+
# @return [CF::String, CF::Data]
|
58
|
+
def to_cf
|
59
|
+
binary? ? to_cf_data : to_cf_string
|
60
|
+
end
|
61
|
+
|
62
|
+
# @!method binary?
|
63
|
+
#
|
64
|
+
# used to determine whether {#to_cf} should return a {CF::String} or a {CF::Data}.
|
65
|
+
# This simply checks whether the encoding is ascii-8bit or not.
|
66
|
+
#
|
67
|
+
# @return whether the string is handled as binary data or not
|
68
|
+
#
|
69
|
+
def binary?
|
70
|
+
encoding == Encoding::ASCII_8BIT
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param [optional, Boolean, Encoding] bin
|
74
|
+
# If you pass `true` then `Encoding::ASCII_BIT` is used, if you pass `false` then `Encoding::UTF_8`
|
75
|
+
def binary!(bin = true)
|
76
|
+
if bin == true
|
77
|
+
force_encoding Encoding::ASCII_8BIT
|
78
|
+
else
|
79
|
+
# default to utf-8
|
80
|
+
force_encoding(bin == false ? "UTF-8" : bin)
|
81
|
+
end
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns a {CF::String} representing the string
|
86
|
+
# @return [CF::String]
|
87
|
+
def to_cf_string
|
88
|
+
CF::String.from_string self
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns a {CF::Data} representing the string
|
92
|
+
# @return [CF::Data]
|
93
|
+
def to_cf_data
|
94
|
+
CF::Data.from_string self
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Patches for ruby Time
|
99
|
+
refine Time do
|
100
|
+
# Returns a {CF::Date} representing the time.
|
101
|
+
# @return [CF::Date]
|
102
|
+
def to_cf
|
103
|
+
CF::Date.from_time(self)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Patches for ruby Hash
|
108
|
+
refine Hash do
|
109
|
+
# Converts the Hash to an mutable {CF::Dictionary} by calling `to_cf` on each key and value it contains
|
110
|
+
# @return [CF::Dictionary]
|
111
|
+
def to_cf
|
112
|
+
transform_keys! &:to_s # Convert all keys to strings
|
113
|
+
CF::Dictionary.mutable.tap do |r|
|
114
|
+
each do |k, v|
|
115
|
+
r[k.to_cf] = v.to_cf
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|