ObjFW  Check-in [3ad1f2b268]

Overview
Comment:Add OFKeyValueCoding

No support for paths and auto-wrapping yet.

Also, no classes like OFDictionary override it yet.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 3ad1f2b268ce6d737b2a9072c8e8f0f8e91c2cf51200cf4d73afbdcab91445a6
User & Date: js on 2016-06-05 00:01:20
Other Links: manifest | tags
Context
2016-06-05
13:18
Key Value Coding: Implement auto-wrapping check-in: 6a92704355 user: js tags: trunk
00:01
Add OFKeyValueCoding check-in: 3ad1f2b268 user: js tags: trunk
2016-06-04
22:31
OFZIP: Cast app delegate to OFZIP* check-in: c5901029a0 user: js tags: trunk
Changes

Modified src/Makefile from [d07480767f] to [9a38cd4575].

34
35
36
37
38
39
40

41
42
43
44
45
46
47
       OFMutableArray.m			\
       OFMutableDictionary.m		\
       OFMutableSet.m			\
       OFMutableString.m		\
       OFNull.m				\
       OFNumber.m			\
       OFObject.m			\

       OFObject+Serialization.m		\
       OFOptionsParser.m		\
       ${OFPROCESS_M}			\
       OFRIPEMD160Hash.m		\
       OFRunLoop.m			\
       OFSeekableStream.m		\
       OFSet.m				\







>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
       OFMutableArray.m			\
       OFMutableDictionary.m		\
       OFMutableSet.m			\
       OFMutableString.m		\
       OFNull.m				\
       OFNumber.m			\
       OFObject.m			\
       OFObject+KeyValueCoding.m	\
       OFObject+Serialization.m		\
       OFOptionsParser.m		\
       ${OFPROCESS_M}			\
       OFRIPEMD160Hash.m		\
       OFRunLoop.m			\
       OFSeekableStream.m		\
       OFSet.m				\
112
113
114
115
116
117
118

119
120
121
122
123
124
125
	       OFThreadPool.m		\
	       threading.m

INCLUDES := ${SRCS:.m=.h}			\
	    OFCollection.h			\
	    OFHash.h				\
	    OFJSONRepresentation.h		\

	    OFLocking.h				\
	    OFMessagePackRepresentation.h	\
	    OFSerialization.h			\
	    OFTLSSocket.h			\
	    ObjFW.h				\
	    autorelease.h			\
	    ${ATOMIC_H}				\







>







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
	       OFThreadPool.m		\
	       threading.m

INCLUDES := ${SRCS:.m=.h}			\
	    OFCollection.h			\
	    OFHash.h				\
	    OFJSONRepresentation.h		\
	    OFKeyValueCoding.h			\
	    OFLocking.h				\
	    OFMessagePackRepresentation.h	\
	    OFSerialization.h			\
	    OFTLSSocket.h			\
	    ObjFW.h				\
	    autorelease.h			\
	    ${ATOMIC_H}				\

Added src/OFKeyValueCoding.h version [3dd35e7786].







































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
 *   Jonathan Schleifer <js@heap.zone>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

@class OFString;

/*!
 * @protocol OFKeyValueCoding OFKeyValueCoding.h ObjFW/OFKeyValueCoding.h
 *
 * @brief A protocol for Key Value Coding.
 *
 * Key Value Coding makes it possible to access properties dynamically using
 * the interface described by this protocol.
 */
@protocol OFKeyValueCoding
/*!
 * @brief Return the value for the specified key
 *
 * @param key The key of the value to return
 * @return The value for the specified key
 */
- (id)valueForKey: (OFString*)key;

/*!
 * @brief This is called by @ref valueForKey: if the specified key does not
 *	  exist.
 *
 * By default, this throws an @ref OFUndefinedKeyException.
 *
 * @param key The undefined key of the value to return
 * @return The value for the specified undefined key
 */
- (id)valueForUndefinedKey: (OFString*)key;

/*!
 * @brief Set the value for the specified key
 *
 * @param value The value for the specified key
 * @param key The key of the value to set
 */
- (void)setValue: (id)value
	  forKey: (OFString*)key;

/*!
 * @brief This is called by @ref setValue:forKey: if the specified key does not
 *	  exist.
 *
 * By default, this throws an @ref OFUndefinedKeyException.
 *
 * @param value The value for the specified undefined key
 * @param key The undefined key of the value to set
 */
-  (void)setValue: (id)value
  forUndefinedKey: (OFString*)key;
@end

Added src/OFObject+KeyValueCoding.h version [1c62947d53].



































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
 *   Jonathan Schleifer <js@heap.zone>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFObject.h"
#import "OFKeyValueCoding.h"

OF_ASSUME_NONNULL_BEGIN

#ifdef __cplusplus
extern "C" {
#endif
extern int _OFObject_KeyValueCoding_reference;
#ifdef __cplusplus
}
#endif

@interface OFObject (KeyValueCoding) <OFKeyValueCoding>
@end

OF_ASSUME_NONNULL_END

Added src/OFObject+KeyValueCoding.m version [76ddc597a2].







































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
 *   Jonathan Schleifer <js@heap.zone>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdlib.h>
#include <ctype.h>

#import "OFObject.h"
#import "OFObject+KeyValueCoding.h"
#import "OFString.h"
#import "OFNull.h"

#import "OFOutOfMemoryException.h"
#import "OFUndefinedKeyException.h"

int _OFObject_KeyValueCoding_reference;

static bool
checkTypeEncoding(const char *typeEncoding, char returnType, ...)
{
	va_list args;
	char type;

	if (typeEncoding == NULL)
		return false;

	if (*typeEncoding++ != returnType)
		return false;

	while (*typeEncoding >= '0' && *typeEncoding <= '9')
		typeEncoding++;

	va_start(args, returnType);

	while ((type = va_arg(args, int)) != 0) {
		if (*typeEncoding++ != type)
			return false;

		while (*typeEncoding >= '0' && *typeEncoding <= '9')
			typeEncoding++;
	}

	if (*typeEncoding != '\0')
		return false;

	return true;
}

@implementation OFObject (KeyValueCoding)
- (id)valueForKey: (OFString*)key
{
	SEL selector = sel_registerName([key UTF8String]);
	const char *typeEncoding = [self typeEncodingForSelector: selector];

	if (!checkTypeEncoding(typeEncoding, '@', '@', ':', 0))
		return [self valueForUndefinedKey: key];

	return [self performSelector: selector];
}

- (id)valueForUndefinedKey: (OFString*)key
{
	@throw [OFUndefinedKeyException exceptionWithObject: self
							key: key];
}

- (void)setValue: (id)value
	  forKey: (OFString*)key
{
	char *name;
	size_t keyLength;
	SEL selector;
	const char *typeEncoding;
	id (*setter)(id, SEL, id);

	keyLength = [key UTF8StringLength];

	if (keyLength < 1) {
		[self	 setValue: value
		  forUndefinedKey: key];
		return;
	}

	if ((name = malloc(keyLength + 5)) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithRequestedSize: keyLength + 5];

	memcpy(name, "set", 3);
	memcpy(name + 3, [key UTF8String], keyLength);
	memcpy(name + keyLength + 3, ":", 2);

	name[3] = toupper(name[3]);

	selector = sel_registerName(name);

	free(name);

	typeEncoding = [self typeEncodingForSelector: selector];

	if (!checkTypeEncoding(typeEncoding, 'v', '@', ':', '@', 0)) {
		[self	 setValue: value
		  forUndefinedKey: key];
		return;
	}

	setter = (id(*)(id, SEL, id))[self methodForSelector: selector];
	setter(self, selector, value);
}

-  (void)setValue: (id)value
  forUndefinedKey: (OFString*)key
{
	@throw [OFUndefinedKeyException exceptionWithObject: self
							key: key
						      value: value];
}
@end

Modified src/OFObject.h from [5b937156e8] to [fb4f549aa8].

963
964
965
966
967
968
969

970
extern uint32_t of_hash_seed;
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END


#import "OFObject+Serialization.h"







>

963
964
965
966
967
968
969
970
971
extern uint32_t of_hash_seed;
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END

#import "OFObject+KeyValueCoding.h"
#import "OFObject+Serialization.h"

Modified src/OFObject.m from [980b1c8958] to [8d3755fc71].

207
208
209
210
211
212
213

214
215
216
217
218
219
220
	    cStringWithEncoding: [OFSystemInfo native8BitEncoding]];
}

/* References for static linking */
void
_references_to_categories_of_OFObject(void)
{

	_OFObject_Serialization_reference = 1;
}

@implementation OFObject
+ (void)load
{
#if !defined(OF_APPLE_RUNTIME) || defined(__OBJC2__)







>







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
	    cStringWithEncoding: [OFSystemInfo native8BitEncoding]];
}

/* References for static linking */
void
_references_to_categories_of_OFObject(void)
{
	_OFObject_KeyValueCoding_reference = 1;
	_OFObject_Serialization_reference = 1;
}

@implementation OFObject
+ (void)load
{
#if !defined(OF_APPLE_RUNTIME) || defined(__OBJC2__)

Modified src/exceptions/Makefile from [4a66a083dc] to [0569261c12].

37
38
39
40
41
42
43

44
45
46
47
48
49
50
       OFSeekFailedException.m				\
       OFSetOptionFailedException.m			\
       OFStatItemFailedException.m			\
       OFStillLockedException.m				\
       OFTruncatedDataException.m			\
       OFUnboundNamespaceException.m			\
       OFUnboundPrefixException.m			\

       OFUnknownXMLEntityException.m			\
       OFUnlockFailedException.m			\
       OFUnsupportedProtocolException.m			\
       OFUnsupportedVersionException.m			\
       OFWriteFailedException.m				\
       ${USE_SRCS_SOCKETS}				\
       ${USE_SRCS_THREADS}







>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
       OFSeekFailedException.m				\
       OFSetOptionFailedException.m			\
       OFStatItemFailedException.m			\
       OFStillLockedException.m				\
       OFTruncatedDataException.m			\
       OFUnboundNamespaceException.m			\
       OFUnboundPrefixException.m			\
       OFUndefinedKeyException.m			\
       OFUnknownXMLEntityException.m			\
       OFUnlockFailedException.m			\
       OFUnsupportedProtocolException.m			\
       OFUnsupportedVersionException.m			\
       OFWriteFailedException.m				\
       ${USE_SRCS_SOCKETS}				\
       ${USE_SRCS_THREADS}

Added src/exceptions/OFUndefinedKeyException.h version [62c355b2c5].





























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
 *   Jonathan Schleifer <js@heap.zone>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFException.h"

/*!
 * @class OFUndefinedKeyException \
 *	  OFUndefinedKeyException.h ObjFW/OFUndefinedKeyException.h
 *
 * @brief An exception indicating that a key for Key Value Coding is undefined.
 */
@interface OFUndefinedKeyException: OFException
{
	id _object;
	OFString *_key;
	id _value;
}

/*!
 * The object on which the key is undefined.
 */
@property (readonly, retain) id object;

/*!
 * The key which is undefined.
 */
@property (readonly, copy) OFString *key;

/*!
 * The value for the undefined key
 */
@property (readonly, retain) id value;

/*!
 * @brief Creates a new, autoreleased undefined key exception.
 *
 * @param object The object on which the key is undefined
 * @param key The key which is undefined
 *
 * @return A new, autoreleased undefined key exception
 */
+ (instancetype)exceptionWithObject: (id)object
				key: (OFString*)key;

/*!
 * @brief Creates a new, autoreleased undefined key exception.
 *
 * @param object The object on which the key is undefined
 * @param key The key which is undefined
 * @param value The value for the undefined key
 *
 * @return A new, autoreleased undefined key exception
 */
+ (instancetype)exceptionWithObject: (id)object
				key: (OFString*)key
			      value: (id)value;

/*!
 * @brief Initializes an already allocated undefined key exception.
 *
 * @param object The object on which the key is undefined
 * @param key The key which is undefined
 *
 * @return An initialized undefined key exception
 */
- initWithObject: (id)object
	     key: (OFString*)key;

/*!
 * @brief Initializes an already allocated undefined key exception.
 *
 * @param object The object on which the key is undefined
 * @param key The key which is undefined
 * @param value The value for the undefined key
 *
 * @return An initialized undefined key exception
 */
- initWithObject: (id)object
	     key: (OFString*)key
	   value: (id)value;
@end

Added src/exceptions/OFUndefinedKeyException.m version [4e1ca20fa6].































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
 *   Jonathan Schleifer <js@heap.zone>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#import "OFUndefinedKeyException.h"
#import "OFString.h"

@implementation OFUndefinedKeyException
@synthesize object = _object, key = _key, value = _value;

+ (instancetype)exceptionWithObject: (id)object
				key: (OFString*)key
{
	return [[[self alloc] initWithObject: object
					 key: key] autorelease];
}

+ (instancetype)exceptionWithObject: (id)object
				key: (OFString*)key
			      value: (id)value
{
	return [[[self alloc] initWithObject: object
					 key: key
				       value: value] autorelease];
}

- init
{
	OF_INVALID_INIT_METHOD
}

- initWithObject: (id)object
	     key: (OFString*)key
{
	self = [super init];

	@try {
		_object = [object retain];
		_key = [key copy];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- initWithObject: (id)object
	     key: (OFString*)key
	   value: (id)value
{
	self = [super init];

	@try {
		_object = [object retain];
		_key = [key copy];
		_value = [value retain];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_object release];
	[_key release];
	[_value release];

	[super dealloc];
}

- (OFString*)description
{
	return [OFString stringWithFormat:
	    @"The key \"%@\" is undefined for an object of type %@!",
	    _key, [_object className]];
}
@end