require_relative '../base' module Analytics module Serializer class ObjC < Base class Event def initialize(src) @src = src end def save(path) @class_name = 'AnalyticsEvent' @file_name = @class_name + '.h' output_path = File.join(path, @file_name) File.write(output_path, render_h) @file_name = @class_name + '.m' output_path = File.join(path, @file_name) File.write(output_path, render_m) end private def render_h ERB.new(template_h, nil, '-').result(binding) end def template_h <<~TEMPLATE <%= ERB.new(Analytics::Templates.tmpl_at('header.erb')).result(binding) %> #import #import "AnalyticsEnums.h" NS_ASSUME_NONNULL_BEGIN __swift_unavailable("This class is only available in ObjC.") @interface <%= @class_name %> : NSObject @property (nonatomic, strong, readonly) NSString *name; @property (nonatomic, strong, readonly, nullable) NSDictionary *properties; - (instancetype)init NS_UNAVAILABLE; + (instancetype)new NS_UNAVAILABLE; # pragma mark - Events <% @src["events"].each do |event| -%> /// <%= event["description"] %> <% if event["properties"].nil? -%> + (instancetype)<%= event["name"].camel_case %>; <% else -%> <% event['properties'].each do |property| -%> /// @param <%= property['name'].camel_case %> <%= property['description'] %> <% end -%> + (instancetype)<%= event["name"].camel_case -%><%= format_method_params(event['properties']) %>; <% end %> <% end -%> @end NS_ASSUME_NONNULL_END TEMPLATE end def render_m ERB.new(template_m, nil, '-').result(binding) end def template_m <<~TEMPLATE <%= ERB.new(Analytics::Templates.tmpl_at('header.erb')).result(binding) %> #import "<%= @class_name + '.h' %>" @implementation <%= @class_name %> - (instancetype)initWithName:(NSString *)name properties:(NSDictionary *)properties { if (self = [super init]) { _name = name; _properties = properties; } return self; } # pragma mark - Events <% @src['events'].each do |event| -%> <% if event['properties'].nil? -%> + (instancetype)<%= event['name'].camel_case %> { return [[self alloc] initWithName:@"<%= event['name'] %>" properties: nil]; } <% else -%> + (instancetype)<%= event['name'].camel_case -%><%= format_method_params(event['properties']) %> { <% Interactor::Event.enum_properties_from_event(event).each do |property| -%> NSString *<%= property['name'].camel_case %>Value; switch (<%= property['name'].camel_case %>) { <% property['values'].each do |value| -%> case <%= 'AE' + property['name'].pascal_case + value.pascal_case %>: <%= property['name'].camel_case %>Value = @"<%= value %>"; break; <% end -%> } <% end -%> return [[self alloc] initWithName:@"<%= event['name'] %>" properties: <%= format_init_properties(event['properties']) %>]; } <% end -%> <% end -%> @end TEMPLATE end ## Helper methods called from the ERB template # Formats the parameters in ObjC method. def format_method_params(properties) params = properties.map.with_index do |property, i| name = if i == 0 property['name'].pascal_case # 'num_of_items' -> 'NumOfItems' else property['name'].camel_case # 'num_of_items' -> 'numOfItems' end "#{name}:(#{format_property_type(property)})#{property['name'].camel_case}" end "With#{params.join(' ')}" end # Maps the property type to ObjC type. def format_property_type(property) # if it doesn't have values, it's not an enum, # and if it does, we'll return capitalized property name prefixed with 'AE', # because an enum with the same name will be generated as well if property['values'].nil? case property['type'] when 'text' 'NSString *' when 'number' 'NSInteger' when 'decimal' 'double' else 'unknown-type' end else 'AE' + property['name'].pascal_case end end # Formats the properties passed to Event's init. def format_init_properties(properties) result = properties .map.with_index { |property, _i| "@\"#{property['name']}\": #{format_init_property_value(property)}" } .join(', ') "@{#{result}}" end # Formats the property's value (used as NSDictionary's value) value depending on the property's type. def format_init_property_value(property) # if it doesn't have values, it's not an enum if property['values'].nil? case property['type'] when 'number', 'decimal' "@(#{property['name'].camel_case})" else property['name'].camel_case end else property['name'].camel_case + 'Value' end end end end end end