lib/evva/android_generator.rb in evva-0.3.0 vs lib/evva/android_generator.rb in evva-0.4.0
- old
+ new
@@ -4,119 +4,162 @@
def initialize(package_name)
@package_name = package_name
end
- NATIVE_TYPES = %w[Long Int String Double Float Boolean].freeze
+ BASE_TEMPLATE = File.expand_path("./templates/kotlin/base.kt", __dir__)
+ EVENTS_TEMPLATE = File.expand_path("./templates/kotlin/events.kt", __dir__)
+ EVENT_ENUM_TEMPLATE = File.expand_path("./templates/kotlin/event_enum.kt", __dir__)
+ PEOPLE_PROPERTIES_TEMPLATE = File.expand_path("./templates/kotlin/people_properties.kt", __dir__)
+ PEOPLE_PROPERTIES_ENUM_TEMPLATE = File.expand_path("./templates/kotlin/people_properties_enum.kt", __dir__)
+ SPECIAL_PROPERTY_ENUMS_TEMPLATE = File.expand_path("./templates/kotlin/special_property_enums.kt", __dir__)
+ DESTINATIONS_TEMPLATE = File.expand_path("./templates/kotlin/destinations.kt", __dir__)
- def events(bundle, file_name)
+ TAB_SIZE = " " # \t -> 4 spaces
+
+ NATIVE_TYPES = %w[Long Int String Double Float Boolean Date].freeze
+
+ def events(bundle, file_name, enums_file_name, destinations_file_name)
header_footer_wrapper do
-"""sealed class #{file_name}(event: AnalyticsEvents) {
-\tval name = event.key
+ class_name = file_name
+ enums_class_name = enums_file_name
+ destinations_class_name = destinations_file_name
-\topen val properties: Map<String, Any?>? = null
+ events = bundle.map do |event|
+ properties = event.properties.map do |name, type|
+ param_name = camelize(name.to_s, false)
+ value_fetcher = param_name
-#{bundle.map { |e| event_class(e, file_name) }.join("\n\n")}
-}"""
- end
- end
+ if is_special_property?(type)
+ if type.end_with?('?')
+ # optional value, we need ? to access a parameter
+ value_fetcher += "?"
+ end
+ value_fetcher += ".key"
+ end
- def people_properties(people_bundle, file_name)
- header_footer_wrapper do
- body = "enum class #{file_name}(val key: String) {\n"
- body << people_bundle.map { |prop| "\t#{prop.upcase}(\"#{prop}\")" }.join(",\n")
- body << ";\n}"
+ {
+ param_name: param_name,
+ value_fetcher: value_fetcher,
+ type: type,
+ name: name.to_s,
+ }
+ end
+
+ destinations = event.destinations.map { |p| constantize(p) }
+
+ {
+ class_name: camelize(event.event_name),
+ event_name: constantize(event.event_name),
+ properties: properties,
+ destinations: destinations,
+ is_object: properties.count == 0 && destinations.count == 0,
+ }
+ end
+
+ template_from(EVENTS_TEMPLATE).result(binding)
end
end
def event_enum(bundle, file_name)
header_footer_wrapper do
- body = "enum class #{file_name}(val key: String) {\n"
- body << bundle.map(&:event_name).map { |prop| "\t#{prop.upcase}(\"#{prop}\")" }.join(",\n")
- body << ";\n}"
+ class_name = file_name
+
+ events = bundle.map(&:event_name).map do |event_name|
+ {
+ name: constantize(event_name),
+ value: event_name,
+ }
+ end
+
+ template_from(EVENT_ENUM_TEMPLATE).result(binding)
end
end
- def special_property_enums(enums)
+ def people_properties(people_bundle, file_name, enums_file_name, destinations_file_name)
header_footer_wrapper do
- enums.map do |enum|
- body = "enum class #{enum.enum_name}(val key: String) {\n"
- body << enum.values.map { |vals| "\t#{vals.tr(' ', '_').upcase}(\"#{vals}\")"}.join(",\n")
- body << ";\n}"
- end.join("\n\n")
+ class_name = file_name
+ enums_class_name = enums_file_name
+ destinations_class_name = destinations_file_name
+
+ properties = people_bundle.map do |property|
+ {
+ class_name: camelize(property.property_name),
+ property_name: constantize(property.property_name),
+ type: property.type,
+ is_special_property: is_special_property?(property.type),
+ destinations: property.destinations.map { |p| constantize(p) },
+ }
+ end
+
+ template_from(PEOPLE_PROPERTIES_TEMPLATE).result(binding)
end
end
- private
+ def people_properties_enum(people_bundle, file_name)
+ header_footer_wrapper do
+ class_name = file_name
- def imports_header(imports = [])
- return unless imports.length > 0
- imports.map { |ev| ev. gsub("packagename", @package_name) }
- .join("\n") + "\n\n"
+ properties = people_bundle.map(&:property_name).map do |property_name|
+ {
+ name: constantize(property_name),
+ value: property_name,
+ }
+ end
+
+ template_from(PEOPLE_PROPERTIES_ENUM_TEMPLATE).result(binding)
+ end
end
- def header_footer_wrapper(imports = [])
-<<-Kotlin
-package #{@package_name}
+ def special_property_enums(enums_bundle)
+ header_footer_wrapper do
+ enums = enums_bundle.map do |enum|
+ values = enum.values.map do |value|
+ {
+ name: constantize(value),
+ value: value,
+ }
+ end
-#{imports_header(imports)}/**
- * This file was automatically generated by evva: https://github.com/hole19/evva
- */
+ {
+ class_name: enum.enum_name,
+ values: values,
+ }
+ end
-#{yield.gsub("\t", " ")}
-Kotlin
+ template_from(SPECIAL_PROPERTY_ENUMS_TEMPLATE).result(binding)
+ end
end
- def event_class(event_data, superclass_name)
- class_name = camelize(event_data.event_name)
- class_arguments = event_data.properties.map { |name, type| "val #{camelize(name, false)}: #{type}" }.join(', ')
- if !class_arguments.empty?
- props = props_map(event_data.properties)
+ def destinations(bundle, file_name)
+ header_footer_wrapper do
+ class_name = file_name
-"""\tdata class #{class_name}(
-\t\t#{class_arguments}
-\t) : #{superclass_name}(AnalyticsEvents.#{event_data.event_name.upcase}) {
-#{props}
-\t}"""
+ destinations = bundle.map { |d| constantize(d) }
- else
-"""\tobject #{class_name} : #{superclass_name}(AnalyticsEvents.#{event_data.event_name.upcase})"""
+ template_from(DESTINATIONS_TEMPLATE).result(binding)
end
end
- def props_map(properties)
- split_properties =
- properties
- .map.with_index do |data, index|
- name, type = data
- prop = "\t\t\t\"#{name}\" to #{camelize(name, false)}"
+ private
- if special_property?(type)
- if optional_property?(type)
- prop = "#{prop}?"
- end
- prop = "#{prop}.key"
- end
+ def header_footer_wrapper
+ package_name = @package_name
- if index < properties.size - 1
- # add list comma to every property except the last one
- prop = "#{prop},"
- end
+ content = yield
+ .chop # trim trailing newlines created by sublime
- prop
- end
- .join("\n")
-
- "\t\toverride val properties = mapOf(\n#{split_properties}\n\t\t)"
+ template_from(BASE_TEMPLATE).result(binding).gsub("\t", TAB_SIZE)
end
- def special_property?(type)
- !NATIVE_TYPES.include?(type.chomp('?'))
- end
+ def template_from(path)
+ file = File.read(path)
- def optional_property?(type)
- type.include?('?')
+ # - 2nd argument (nil) changes nothing
+ # - 3rd argument activates trim mode using "-" so that you can decide to
+ # not include a line (useful on loops and if statements)
+ ERB.new(file, nil, '-')
end
# extracted from Rails' ActiveSupport
def camelize(string, uppercase_first_letter = true)
string = string.to_s
@@ -124,8 +167,16 @@
string = string.sub(/^[a-z\d]*/) { |match| match.capitalize }
else
string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
end
string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub("/", "::")
+ end
+
+ def constantize(string)
+ string.tr(' ', '_').upcase
+ end
+
+ def is_special_property?(type)
+ !NATIVE_TYPES.include?(type.chomp('?'))
end
end
end