Created
January 21, 2025 10:21
-
-
Save Frityet/884bfcb3b9be5e96a9f43616530527a2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <objc/runtime.h> | |
@interface HTMLNode : NSObject | |
@property (nonatomic, copy) NSString *tag; | |
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSString *> *attributes; | |
@property (nonatomic, strong) NSMutableArray *children; | |
+ (instancetype)element: (NSString *)tag; | |
- (NSString *)description; | |
@end | |
@implementation HTMLNode | |
+ (instancetype)element:(NSString *)tag { | |
HTMLNode *node = [[HTMLNode alloc] init]; | |
node.tag = tag; | |
node.attributes = [NSMutableDictionary dictionary]; | |
node.children = [NSMutableArray array]; | |
return node; | |
} | |
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { | |
NSString *selString = NSStringFromSelector(sel); | |
NSUInteger colonCount = 0; | |
for (NSUInteger i = 0; i < selString.length; i++) { | |
if ([selString characterAtIndex:i] == ':') colonCount++; | |
} | |
NSMutableString *types = [NSMutableString stringWithString:@"@@:"]; | |
for (NSUInteger i = 0; i < colonCount; i++) { | |
[types appendString:@"@"]; | |
} | |
return [NSMethodSignature signatureWithObjCTypes:types.UTF8String]; | |
} | |
- (void)forwardInvocation:(NSInvocation *)invocation { | |
NSString *selString = NSStringFromSelector(invocation.selector); | |
if ([selString hasSuffix:@":"]) { | |
selString = [selString substringToIndex:selString.length - 1]; | |
} | |
NSArray *parts = [selString componentsSeparatedByString:@":"]; | |
for (NSUInteger i = 0; i < parts.count; i++) { | |
__unsafe_unretained id value; | |
[invocation getArgument:&value atIndex:(i + 2)]; | |
NSString *key = parts[i]; | |
if ([key isEqualToString:@"children"]) { | |
if ([value isKindOfClass:[NSArray class]]) { | |
[self.children addObjectsFromArray:value]; | |
} else { | |
[self.children addObject:value]; | |
} | |
} else { | |
self.attributes[key] = value; | |
} | |
} | |
HTMLNode *result = self; | |
[invocation setReturnValue:&result]; | |
} | |
- (NSString *)description { | |
NSMutableString *html = [NSMutableString stringWithFormat:@"<%@", self.tag]; | |
for (NSString *key in self.attributes) { | |
[html appendFormat:@" %@=\"%@\"", key, self.attributes[key]]; | |
} | |
[html appendString:@">"]; | |
for (id child in self.children) { | |
[html appendString:[child description]]; | |
} | |
[html appendFormat:@"</%@>", self.tag]; | |
return html; | |
} | |
@end | |
#define $node(...) [HTMLNode element: @#__VA_ARGS__] | |
#define html $node(html) | |
#define head $node(head) | |
#define body $node(body) | |
#define h1 $node(h1) | |
#define p $node(p) | |
int main() | |
{ | |
#pragma clang diagnostic ignored "-Wobjc-method-access" | |
HTMLNode *doc = [html children: @[ | |
[body children: @[ | |
[h1 class: @"header" children: @"Hello!"], | |
[p class: @"para" id: @"main" children: @"this is a paragraph"] | |
]] | |
]]; | |
NSLog(@"%@", doc); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment