def _get_imports_m(self, data_types, default_imports): """Emits all necessary implementation file imports for the given Stone data type.""" if not isinstance(data_types, list): data_types = [data_types] import_classes = default_imports for data_type in data_types: import_classes.append(fmt_class_prefix(data_type)) if data_type.parent_type: import_classes.append(fmt_class_prefix(data_type.parent_type)) if is_struct_type( data_type) and data_type.has_enumerated_subtypes(): for tags, subtype in data_type.get_all_subtypes_with_tags(): import_classes.append(fmt_class_prefix(subtype)) for field in data_type.all_fields: data_type, _ = unwrap_nullable(field.data_type) # unpack list while is_list_type(data_type): data_type = data_type.data_type if is_user_defined_type(data_type): import_classes.append(fmt_class_prefix(data_type)) if import_classes: import_classes = list(set(import_classes)) import_classes.sort() return import_classes
def block_h_from_data_type(self, data_type, protocol=None): assert is_user_defined_type(data_type), \ 'Expected user-defined type, got %r' % type(data_type) if not protocol: extensions = [] if data_type.parent_type and is_struct_type(data_type): extensions.append(fmt_class_prefix(data_type.parent_type)) else: if is_union_type(data_type): # Use a handwritten base class extensions.append('NSObject') else: extensions.append('NSObject') extend_suffix = ' : {}'.format( ', '.join(extensions)) if extensions else '' else: base = fmt_class_prefix(data_type.parent_type) if ( data_type.parent_type and not is_union_type(data_type)) else 'NSObject' extend_suffix = ' : {} <{}>'.format(base, ', '.join(protocol)) with self.block('@interface {}{}'.format( fmt_class_prefix(data_type), extend_suffix), delim=('', '@end'), dent=0): self.emit() yield
def _get_imports_h(self, data_types): """Emits all necessary header file imports for the given Stone data type.""" if not isinstance(data_types, list): data_types = [data_types] import_classes = [] for data_type in data_types: if is_user_defined_type(data_type): import_classes.append(fmt_class_prefix(data_type)) for field in data_type.all_fields: data_type, _ = unwrap_nullable(field.data_type) # unpack list while is_list_type(data_type): data_type = data_type.data_type if is_user_defined_type(data_type): import_classes.append(fmt_class_prefix(data_type)) import_classes = list(set(import_classes)) import_classes.sort() return import_classes
def block_h_from_data_type(self, data_type, protocol=None): assert is_user_defined_type(data_type), \ 'Expected user-defined type, got %r' % type(data_type) if not protocol: extensions = [] if data_type.parent_type and is_struct_type(data_type): extensions.append(fmt_class_prefix(data_type.parent_type)) else: if is_union_type(data_type): # Use a handwritten base class extensions.append('NSObject') else: extensions.append('NSObject') extend_suffix = ' : {}'.format( ', '.join(extensions)) if extensions else '' else: base = fmt_class_prefix(data_type.parent_type) if ( data_type.parent_type and not is_union_type(data_type)) else 'NSObject' extend_suffix = ' : {} <{}>'.format(base, ', '.join(protocol)) with self.block('@interface {}{}'.format(fmt_class_prefix(data_type), extend_suffix), delim=('', '@end'), dent=0): self.emit() yield
def _get_imports_m(self, data_types, default_imports): """Emits all necessary implementation file imports for the given Stone data type.""" if not isinstance(data_types, list): data_types = [data_types] import_classes = default_imports for data_type in data_types: import_classes.append(fmt_class_prefix(data_type)) if data_type.parent_type: import_classes.append(fmt_class_prefix(data_type.parent_type)) if is_struct_type(data_type) and data_type.has_enumerated_subtypes(): for _, subtype in data_type.get_all_subtypes_with_tags(): import_classes.append(fmt_class_prefix(subtype)) for field in data_type.all_fields: data_type, _ = unwrap_nullable(field.data_type) # unpack list while is_list_type(data_type): data_type = data_type.data_type if is_user_defined_type(data_type): import_classes.append(fmt_class_prefix(data_type)) if import_classes: import_classes = list(set(import_classes)) import_classes.sort() return import_classes
def _get_imports_h(self, data_types): """Emits all necessary header file imports for the given Stone data type.""" if not isinstance(data_types, list): data_types = [data_types] import_classes = [] for data_type in data_types: if is_user_defined_type(data_type): import_classes.append(fmt_class_prefix(data_type)) for field in data_type.all_fields: data_type, _ = unwrap_nullable(field.data_type) # unpack list while is_list_type(data_type): data_type = data_type.data_type if is_user_defined_type(data_type): import_classes.append(fmt_class_prefix(data_type)) import_classes = list(set(import_classes)) import_classes.sort() return import_classes
def _fmt_default(self, data_type): data_type, nullable = unwrap_nullable(data_type) result = 'DEFAULT' if nullable: return 'nil' if is_user_defined_type(data_type): result = fmt_func_call(fmt_alloc_call(fmt_class_prefix(data_type)), 'init', []) elif is_list_type(data_type): result = fmt_func_call(fmt_alloc_call('NSArray'), 'init', []) elif is_numeric_type(data_type): if is_float_type(data_type): result = '[NSNumber numberWithDouble:5]' else: result = '[NSNumber numberWithInt:5]' elif is_timestamp_type(data_type): result = '[[NSDateFormatter new] setDateFormat:[self convertFormat:@"test"]]' elif is_string_type(data_type): result = '@"teststring"' elif is_boolean_type(data_type): result = '@YES' return result
def _generate_route_m(self, route, namespace, route_args, extra_args, task_type_name, func_suffix): """Generates route method implementation for the given route.""" user_args = list(route_args) transport_args = [ ('route', 'route'), ('arg', 'arg' if not is_void_type(route.arg_data_type) else 'nil'), ] for name, value, typ in extra_args: user_args.append((name, typ.replace(' _Nonnull', '').replace(' _Nullable', ''))) transport_args.append((name, value)) route_result_type = fmt_type( route.result_data_type, tag=False) if not is_void_type(route.result_data_type) else '' with self.block_func(func='{}{}'.format(fmt_var(route.name), func_suffix), args=fmt_func_args_declaration(user_args), return_type='{} *'.format(task_type_name)): self.emit('DBRoute *route = {}.{};'.format( fmt_route_obj_class(namespace.name), fmt_route_var(namespace.name, route.name))) if is_union_type(route.arg_data_type): self.emit('{} *arg = {};'.format( fmt_class_prefix(route.arg_data_type), fmt_var(route.arg_data_type.name))) elif not is_void_type(route.arg_data_type): init_call = fmt_func_call( caller=fmt_alloc_call( caller=fmt_class_prefix(route.arg_data_type)), callee=self._cstor_name_from_fields_names(route_args), args=fmt_func_args([(f[0], f[0]) for f in route_args])) self.emit('{} *arg = {};'.format( fmt_class_prefix(route.arg_data_type), init_call)) request_call = fmt_func_call(caller='self.client', callee='request{}'.format( fmt_camel_upper( route.attrs.get('style'))), args=fmt_func_args(transport_args)) self.emit('return {};'.format(request_call)) self.emit()
def _generate_init_imports_h(self, data_type): self.emit('#import <Foundation/Foundation.h>') self.emit() self.emit('#import "DBSerializableProtocol.h"') if data_type.parent_type and not is_union_type(data_type): self.emit(fmt_import(fmt_class_prefix(data_type.parent_type))) self.emit()
def _generate_init_imports_h(self, data_type): self.emit('#import <Foundation/Foundation.h>') self.emit() self.emit('#import "DBSerializableProtocol.h"') if data_type.parent_type and not is_union_type(data_type): self.emit(fmt_import(fmt_class_prefix(data_type.parent_type))) self.emit()
def generate(self, api): for namespace in api.namespaces.values(): for data_type in namespace.linearize_data_types(): obj_name_to_namespace[data_type.name] = fmt_class_prefix( data_type) for namespace in api.namespaces.values(): if namespace.routes: import_classes = [ fmt_routes_class(namespace.name), fmt_route_obj_class(namespace.name), self.args.transport_client_name, 'DBStoneBase', 'DBErrors', ] with self.output_to_relative_path('Routes/{}.m'.format( fmt_routes_class(namespace.name))): self.emit_raw(stone_warning) imports_classes_m = import_classes + \ self._get_imports_m( self._get_namespace_route_imports(namespace), []) self._generate_imports_m(imports_classes_m) self._generate_routes_m(namespace) with self.output_to_relative_path('Routes/{}.h'.format( fmt_routes_class(namespace.name))): self.emit_raw(base_file_comment) self.emit('#import <Foundation/Foundation.h>') self.emit() self.emit(fmt_import('DBTasks')) self.emit() import_classes_h = [ self.args.transport_client_name, 'DBNilObject', ] import_classes_h = import_classes_h + self._get_imports_h( self._get_namespace_route_imports( namespace, include_route_args=False, include_route_deep_args=True)) self._generate_imports_h(import_classes_h) self._generate_routes_h(namespace) with self.output_to_relative_path('Client/{}.m'.format( self.args.module_name)): self._generate_client_m(api) with self.output_to_relative_path('Client/{}.h'.format( self.args.module_name)): self._generate_client_h(api)
def _generate_route_m(self, route, namespace, route_args, extra_args, task_type_name, func_suffix): """Generates route method implementation for the given route.""" user_args = list(route_args) transport_args = [ ('route', 'route'), ('arg', 'arg' if not is_void_type(route.arg_data_type) else 'nil'), ] for name, value, typ in extra_args: user_args.append((name, typ)) transport_args.append((name, value)) with self.block_func( func='{}{}'.format(fmt_var(route.name), func_suffix), args=fmt_func_args_declaration(user_args), return_type='{} *'.format(task_type_name)): self.emit('DBRoute *route = {}.{};'.format( fmt_route_obj_class(namespace.name), fmt_route_var(namespace.name, route.name))) if is_union_type(route.arg_data_type): self.emit('{} *arg = {};'.format( fmt_class_prefix(route.arg_data_type), fmt_var(route.arg_data_type.name))) elif not is_void_type(route.arg_data_type): init_call = fmt_func_call( caller=fmt_alloc_call( caller=fmt_class_prefix(route.arg_data_type)), callee=self._cstor_name_from_fields_names(route_args), args=fmt_func_args([(f[0], f[0]) for f in route_args])) self.emit('{} *arg = {};'.format( fmt_class_prefix(route.arg_data_type), init_call)) request_call = fmt_func_call( caller='self.client', callee='request{}'.format( fmt_camel_upper(route.attrs.get('style'))), args=fmt_func_args(transport_args)) self.emit('return {};'.format(request_call)) self.emit()
def generate(self, api): for namespace in api.namespaces.values(): for data_type in namespace.linearize_data_types(): self.obj_name_to_namespace[ data_type.name] = fmt_class_prefix(data_type) for namespace in api.namespaces.values(): if namespace.routes: import_classes = [ fmt_routes_class(namespace.name), fmt_route_obj_class(namespace.name), '{}Protocol'.format(self.args.transport_client_name), 'DBStoneBase', 'DBRequestErrors', ] with self.output_to_relative_path( 'Routes/{}.m'.format(fmt_routes_class(namespace.name))): self.emit_raw(stone_warning) imports_classes_m = import_classes + \ self._get_imports_m( self._get_namespace_route_imports(namespace), []) self._generate_imports_m(imports_classes_m) self._generate_routes_m(namespace) with self.output_to_relative_path( 'Routes/{}.h'.format(fmt_routes_class(namespace.name))): self.emit_raw(base_file_comment) self.emit('#import <Foundation/Foundation.h>') self.emit() self.emit(fmt_import('DBTasks')) self.emit() import_classes_h = [ 'DBNilObject', ] import_classes_h = (import_classes_h + self._get_imports_h(self._get_namespace_route_imports( namespace, include_route_args=False, include_route_deep_args=True))) self._generate_imports_h(import_classes_h) self.emit('@protocol {};'.format(self.args.transport_client_name),) self.emit() self._generate_routes_h(namespace) with self.output_to_relative_path('Client/{}.m'.format(self.args.module_name)): self._generate_client_m(api) with self.output_to_relative_path('Client/{}.h'.format(self.args.module_name)): self._generate_client_h(api)
def _get_example_data(self, example_value, field): data_type, nullable = unwrap_nullable(field.data_type) field_name = fmt_var(field.name) result_args = [] if is_user_defined_type(data_type): obj_args = [] if is_union_type(data_type): for field in data_type.all_fields: if field.name == example_value['.tag']: if not is_void_type(field.data_type): if field.name in example_value: self._get_example_data( example_value[field.name], field) else: self._get_example_data(example_value, field) obj_args.append( (fmt_var(field.name), fmt_var(field.name))) field_value = fmt_func_call( caller=fmt_alloc_call(fmt_class_prefix(data_type)), callee='initWith{}'.format( fmt_camel_upper(example_value['.tag'])), args=fmt_func_args(obj_args)) self.emit('{} *{} = {};'.format(fmt_class_prefix(data_type), field_name, field_value)) else: if data_type.has_enumerated_subtypes(): for tags, subtype in data_type.get_all_subtypes_with_tags( ): assert len(tags) == 1, tags tag = tags[0] if tag == example_value['.tag']: self._get_example_data(example_value, subtype) else: for field in data_type.all_fields: if field.name in example_value: obj_args.append((fmt_var(field.name), self._get_example_data( example_value[field.name], field.data_type))) else: if not is_void_type(field.data_type): obj_args.append( (fmt_var(field.name), self._fmt_default(field.data_type))) field_value = fmt_func_call( fmt_alloc_call(fmt_class_prefix(data_type)), 'initWith{}'.format( fmt_camel_upper(data_type.all_fields[0].name)), fmt_func_args(obj_args)) self.emit('{} *{} = {};'.format( fmt_class_prefix(data_type), field_name, field_value)) result_args.append((field_name, field_name)) elif is_list_type(data_type): if example_value: field_value = '@[{}]'.format( self._get_example_data(example_value[0], field)) else: field_value = 'nil' self.emit('NSArray *{} = {};'.format(field_name, field_value)) result_args.append((field_name, field_name)) elif is_numeric_type(data_type): if is_float_type(data_type): field_value = '[NSNumber numberWithDouble:{}]'.format( example_value) elif isinstance(data_type, (UInt64, Int64)): field_value = '[NSNumber numberWithLong:{}]'.format( example_value) else: field_value = '[NSNumber numberWithInt:{}]'.format( example_value) result_args.append((field_name, field_value)) elif is_timestamp_type(data_type): field_value = '[DbxNSDateSerializer deserialize:@"{}" dateFormat:@"{}"]'.format( example_value, data_type.format) self.emit('NSDate *{} = {};'.format(field_name, field_value)) result_args.append((field_name, field_name)) elif is_string_type(data_type): field_value = '@"{}"'.format(example_value) result_args.append((field_name, field_value)) elif is_boolean_type(data_type): field_value = '@YES' if bool(example_value) else '@NO' result_args.append((field_name, field_value)) return result_args
def _generate_testing_imports(self, api): import_classes = ['DbxStoneSerializers', 'DropboxTransportClient'] for namespace in api.namespaces.values(): for data_type in namespace.linearize_data_types(): import_classes.append(fmt_class_prefix(data_type)) self._generate_imports_m(import_classes)
def _generate_namespace_tests(self, namespace): ns_name = fmt_public_name(namespace.name) self.emit() self.emit( '/// Serialization tests for the {} namespace.'.format(ns_name)) self.emit() self.emit() for data_type in namespace.linearize_data_types(): class_name = fmt_public_name(data_type.name) if is_user_defined_type(data_type): examples = data_type.get_examples() for example_type in examples: test_name = 'testSerialize{}{}{}'.format( ns_name, class_name, fmt_camel_upper(example_type, reserved=False)) with self.block_func(func=test_name, args=[]): self.emit('/// Data from the "{}" example'.format( example_type)) example_data = examples[example_type].value result_args = [] for field in data_type.all_fields: if field.name in example_data: result_args += self._get_example_data( example_data[field.name], field) else: if not is_void_type(field.data_type): result_args.append( (fmt_var(field.name), self._fmt_default(field.data_type))) args_str = fmt_func_args(result_args) if '\n' not in args_str: if is_struct_type( data_type ) and data_type.has_enumerated_subtypes(): for tags, subtype in data_type.get_all_subtypes_with_tags( ): assert len(tags) == 1, tags tag = tags[0] if tag == example_data['.tag']: self.emit('{} *obj = {};'.format( fmt_class_prefix(subtype), self._get_example_data( example_data, subtype))) self.emit( 'NSData *serializedData = [DropboxTransportClient jsonDataWithDictionary:[{} serialize:obj]];' .format(fmt_class_prefix(subtype))) self.emit( 'id jsonObj = [NSJSONSerialization JSONObjectWithData:serializedData options:NSJSONReadingMutableContainers error:nil];' ) self.emit( '{} *outputObj = [{} deserialize:jsonObj];' .format(fmt_class_prefix(subtype), fmt_class_prefix(subtype))) self.emit( '[self checkError:obj outputObj:outputObj];' ) else: self.emit('{} *obj = {};'.format( fmt_class_prefix(data_type), fmt_func_call( fmt_alloc_call( fmt_class_prefix(data_type)), self._cstor_name_from_fields_names( result_args), args_str))) self.emit( 'NSData *serializedData = [DropboxTransportClient jsonDataWithDictionary:[{} serialize:obj]];' .format(fmt_class_prefix(data_type))) self.emit( 'id jsonObj = [NSJSONSerialization JSONObjectWithData:serializedData options:NSJSONReadingMutableContainers error:nil];' ) self.emit( '{} *outputObj = [{} deserialize:jsonObj];' .format(fmt_class_prefix(data_type), fmt_class_prefix(data_type))) self.emit( '[self checkError:obj outputObj:outputObj];' ) self.emit()
def generate(self, api): for namespace in api.namespaces.values(): self.namespace_to_has_routes[namespace] = False if namespace.routes: for route in namespace.routes: if route.attrs.get( 'auth') == self.args.auth_type or route.attrs.get( 'auth' ) == 'noauth' and self.args.auth_type == 'user': self.namespace_to_has_routes[namespace] = True break for namespace in api.namespaces.values(): for data_type in namespace.linearize_data_types(): self.obj_name_to_namespace[data_type.name] = fmt_class_prefix( data_type) for namespace in api.namespaces.values(): if namespace.routes and self.namespace_to_has_routes[namespace]: import_classes = [ fmt_routes_class(namespace.name, self.args.auth_type), fmt_route_obj_class(namespace.name), '{}Protocol'.format(self.args.transport_client_name), 'DBStoneBase', 'DBRequestErrors', ] with self.output_to_relative_path('Routes/{}.m'.format( fmt_routes_class(namespace.name, self.args.auth_type))): self.emit_raw(stone_warning) imports_classes_m = import_classes + \ self._get_imports_m( self._get_namespace_route_imports(namespace), []) self._generate_imports_m(imports_classes_m) self._generate_routes_m(namespace) with self.output_to_relative_path('Routes/{}.h'.format( fmt_routes_class(namespace.name, self.args.auth_type))): self.emit_raw(base_file_comment) self.emit('#import <Foundation/Foundation.h>') self.emit() self.emit(fmt_import('DBTasks')) self.emit() import_classes_h = [ 'DBNilObject', ] import_classes_h = (import_classes_h + self._get_imports_h( self._get_namespace_route_imports( namespace, include_route_args=False, include_route_deep_args=True))) self._generate_imports_h(import_classes_h) self.emit( '@protocol {};'.format( self.args.transport_client_name), ) self.emit() self._generate_routes_h(namespace) with self.output_to_relative_path('Client/{}.m'.format( self.args.module_name)): self._generate_client_m(api) with self.output_to_relative_path('Client/{}.h'.format( self.args.module_name)): self._generate_client_h(api)