{"id":22946586,"url":"https://github.com/mmower/gen","last_synced_at":"2025-08-12T23:32:53.086Z","repository":{"id":4580454,"uuid":"5722275","full_name":"mmower/Gen","owner":"mmower","description":"Objective-C Code Generator","archived":false,"fork":false,"pushed_at":"2012-09-08T21:45:19.000Z","size":152,"stargazers_count":12,"open_issues_count":1,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-20T07:16:35.157Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mmower.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-09-07T20:48:34.000Z","updated_at":"2023-10-26T12:04:19.000Z","dependencies_parsed_at":"2022-08-25T20:40:40.478Z","dependency_job_id":null,"html_url":"https://github.com/mmower/Gen","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmower%2FGen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmower%2FGen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmower%2FGen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmower%2FGen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mmower","download_url":"https://codeload.github.com/mmower/Gen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229717769,"owners_count":18113395,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-14T14:47:22.885Z","updated_at":"2024-12-14T14:47:23.418Z","avatar_url":"https://github.com/mmower.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `Gen`\n## An Objective-C Code Generator\n\nThe `Gen` framework implements an Objective-C code generator that I built it while I was working on Statec (a state machine DSL\n and class generator for Objective-C) and have now extracted into a separate library.\n\n`Gen` is not complete (although I think it models most of the useful parts of Objective-C) and certainly could do with some work\nironing out its kinks. But it works and I think it meets the criteria of being able to do useful work.\n\nIn practice `Gen` provides a set of classes to model Objective-C concepts such as classes (`GenClass`), protocols (`GenProtocol`),\nproperties (`GenProperty`), variables (`GenVariable`), methods (`GenMethod`), and so on. To create a class you create a `GenClass`\ninstance, add properties, methods, protocols, variables and so on. Then add it to a `GenCompilationUnit` that knows how to write\nout the corresponding `.m`/`.h` files.\n\nAt the method level code is inserted into the method body using a template string (essentially `-stringWithFormat:`). In practice\nattempts to model the structure of methods proved to be a somewhat tedious exercise for little reward and I found it easier to\nwork with strings. Though even here `Gen` provides some helper methods to make it easier to do things like invoking `GenMethod`'s.\n\n## Example\n\nHere is a real example of using `Gen`, taken from the source of Statec. This method creates the `.m`/`.h` files for the user-facing\n state machine class. You can see the creation of a class with a private instance variable (i.e. the variable is defined in a class\nextension) that implements a protocol and defines the methods of that protocol. In particular you can see how, when the method\ntagged `start` is being defined it looks up a method in the implementation class and uses the `GenMethod` to create a call to it:\n\n    - (GenCompilationUnit *)generateUnit {\n      NSString *userClassName = [NSString stringWithFormat:@\"%@%@Machine\",\n                                                           [[self machine] prefix],\n                                                           [[self machine] name]];\n\n      GenCompilationUnit *unit = [[GenCompilationUnit alloc] initWithTag:@\"user\"\n                                                                          name:userClassName];\n\n      NSString *versionString = [[[NSBundle mainBundle] infoDictionary] objectForKey:@\"CFBundleShortVersionString\"];\n      NSString *revNumber = [[[NSBundle mainBundle] infoDictionary] objectForKey:@\"CFBundleVersion\"];\n\n      NSMutableString *commentString = [NSMutableString string];\n      [commentString appendFormat:\n          @\"// State machine %@ generated by Statec v%@(%@) on %@\\n\"\n              @\"// Statec copyright (c) 2012 Matt Mower \u003cself@mattmower.com\u003e\\n\"\n              @\"// \\n\",\n          [[self machine] name],\n          versionString,\n          revNumber,\n          [NSDate date]\n      ];\n\n      [unit setComment:commentString];\n\n      // Import the generated machine into the user machine\n      [[unit declarationImports] addObject:[[self implUnit] headerFileName]];\n\n      GenClass *userClass = [[GenClass alloc] initWithTag:@\"user\"\n                                                           name:userClassName\n                                                      baseClass:nil];\n\n      NSString *implVariableName = [NSString stringWithFormat:@\"_%@Machine\", [[[self machine] name] statecStringByLoweringFirstLetter]];\n      GenVariable *implVariable = [[GenVariable alloc] initWithTag:@\"impl\"\n                                                                   scope:GenInstanceScope|GenPrivateScope\n                                                                    name:implVariableName\n                                                                    type:[[[self implUnit] classWithTag:@\"impl\"] pointerType]];\n      [userClass addVariable:implVariable];\n\n      // The delegate protocol is what this class conforms to so stub its methods for the user to implement\n      GenProtocol *delegateProtocol = [[self implUnit] protocolWithTag:@\"delegate\"];\n\n      [userClass addProtocol:delegateProtocol];\n\n      GenMethod *setupMethod = [[GenMethod alloc] initWithTag:@\"setup\"\n                                                              scope:GenInstanceScope|GenPrivateScope\n                                                         returnType:@\"void\"\n                                                     selectorFormat:@\"setup%@Machine\", [[self machine] name]];\n      [[setupMethod body] append:@\"\\t%@ = [[%@ alloc] init];\\n\"\n                                     @\"\\t[%@ setDelegate:self];\",\n                                 [implVariable name],\n                                 [[[self implUnit] classWithTag:@\"impl\"] name],\n                                 [implVariable name]\n      ];\n      [userClass addMethod:setupMethod];\n\n      // Create the initializer that will setup the machine\n      GenMethod *initializer = [[GenMethod alloc] initWithTag:@\"init\"\n                                                              scope:GenInstanceScope\n                                                         returnType:StatecTypeId\n                                                           selector:@selector(init)];\n      [[initializer body] append:@\"\\tself = [super init];\\n\"\n                                     @\"\\tif( self ) {\\n\"\n                                     @\"\\t\\t%@;\\n\"\n                                     @\"\\t}\\n\"\n                                     @\"\\treturn self;\\n\",\n                                 [setupMethod invocationWithReceiver:@\"self\"]\n      ];\n      [initializer setIsDeclaredHere:NO];\n      [userClass addInitializer:initializer];\n\n      /*\n        For the users convenience we will sort the methods into utility methods,\n         non-final state methods, and final state methods.\n       */\n      NSArray *methods = [[delegateProtocol methods] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {\n        return method_weight(obj1) - method_weight(obj2);\n      }];\n\n      for( GenMethod *method in methods ) {\n        GenMethod *stubMethod = [method mutableCopy];\n\n        if( [[method tag] isEqualToString:@\"start\"] ) {\n          GenMethod *startMethod = [[[self implUnit] principalClass] instanceMethodWithTag:@\"start\"];\n          [stubMethod setBody:[[GenStatementGroup alloc] initWithFormat:@\"\\t%@;\", [startMethod invocationWithReceiver:[implVariable name]]]];\n          [stubMethod setIsDeclaredHere:YES];\n        } else {\n          [stubMethod setBody:[[GenStatementGroup alloc] initWithFormat:@\"\\t// Your code here\"]];\n          [stubMethod setIsDeclaredHere:NO];\n        }\n\n        [userClass addMethod:stubMethod];\n      }\n\n\n      [unit addClass:userClass];\n\n      return unit;\n    }\n\n## Feedback\nI'm not sure if anyone else will find `Gen` useful, it's not often that one needs to be able to dynamically generate Objective-C code. But,\nif you do, and you use it, I'd be grateful to hear your feedback.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmower%2Fgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmmower%2Fgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmower%2Fgen/lists"}