evva 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,121 +1,132 @@
1
+ require 'erb'
2
+
1
3
  module Evva
2
4
  class SwiftGenerator
3
- EXTENSION_HEADER =
4
- "\nimport Foundation\n\n"\
5
- "extension Analytics {\n\n".freeze
5
+ BASE_TEMPLATE = File.expand_path("./templates/swift/base.swift", __dir__)
6
+ EVENTS_TEMPLATE = File.expand_path("./templates/swift/events.swift", __dir__)
7
+ PEOPLE_PROPERTIES_TEMPLATE = File.expand_path("./templates/swift/people_properties.swift", __dir__)
8
+ SPECIAL_PROPERTY_ENUMS_TEMPLATE = File.expand_path("./templates/swift/special_property_enums.swift", __dir__)
9
+ DESTINATIONS_TEMPLATE = File.expand_path("./templates/swift/destinations.swift", __dir__)
6
10
 
7
- EXTENSION_FOOTER =
8
- "\n\n}\n"
11
+ TAB_SIZE = " " # \t -> 4 spaces
9
12
 
10
- NATIVE_TYPES = %w[Int String Double Float Bool].freeze
13
+ NATIVE_TYPES = %w[Int String Double Float Bool Date].freeze
11
14
 
12
- def events(bundle, file_name)
15
+ def events(bundle, _file_name, _enums_file_name, _destinations_file_name)
13
16
  header_footer_wrapper do
14
- """\tenum Event {
15
- #{bundle.map { |e| event_case(e) }.join("\n")}
16
-
17
- \t\tvar data: EventData {
18
- \t\t\tswitch self {
19
- #{bundle.map { |e| event_data(e) }.join("\n\n")}
20
- \t\t\t}
21
- \t\t}
22
- \t}"""
17
+ events = bundle.map do |event|
18
+ properties = event.properties.map { |k, v|
19
+ type = native_type(v)
20
+
21
+ value_fetcher = k.to_s
22
+
23
+ if is_special_property?(type)
24
+ if type.end_with?('?')
25
+ # optional value, we need ? to access a parameter
26
+ value_fetcher += "?"
27
+ end
28
+ value_fetcher += ".rawValue"
29
+ end
30
+
31
+ {
32
+ name: k.to_s,
33
+ type: type,
34
+ value: value_fetcher,
35
+ }
36
+ }
37
+
38
+ {
39
+ case_name: camelize(event.event_name),
40
+ event_name: event.event_name,
41
+ properties: properties,
42
+ destinations: event.destinations.map { |p| camelize(p) },
43
+ }
44
+ end
45
+
46
+ template_from(EVENTS_TEMPLATE).result(binding)
23
47
  end
24
48
  end
25
49
 
26
- def event_case(event_data)
27
- function_name = camelize(event_data.event_name)
28
- if event_data.properties.empty?
29
- "\t\tcase #{function_name}"
30
- else
31
- trimmed_properties = event_data.properties.map { |k, v| k.to_s + ': ' + native_type(v) }.join(", ")
32
- "\t\tcase #{function_name}(#{trimmed_properties})"
33
- end
50
+ def event_enum
51
+ # empty
34
52
  end
35
53
 
36
- def event_data(event_data)
37
- function_name = camelize(event_data.event_name)
38
- if event_data.properties.empty?
39
- function_body = "\t\t\tcase .#{function_name}:\n" \
40
- "\t\t\t\treturn EventData(name: \"#{event_data.event_name}\")"
41
- else
42
- function_header = prepend_let(event_data.properties)
43
- function_arguments = dictionary_pairs(event_data.properties)
44
- function_body = "\t\t\tcase .#{function_name}(#{function_header}):\n"\
45
- "\t\t\t\treturn EventData(name: \"#{event_data.event_name}\", properties: [\n"\
46
- "\t\t\t\t\t#{function_arguments.join(",\n\t\t\t\t\t")} ]\n"\
47
- "\t\t\t\t)"
54
+ def people_properties(people_bundle, _file_name, _enums_file_name, _destinations_file_name)
55
+ header_footer_wrapper do
56
+ properties = people_bundle.map do |p|
57
+ type = native_type(p.type)
58
+ {
59
+ case_name: camelize(p.property_name),
60
+ property_name: p.property_name,
61
+ type: type,
62
+ is_special_property: is_special_property?(type),
63
+ destinations: p.destinations.map { |p| camelize(p) },
64
+ }
65
+ end
66
+
67
+ template_from(PEOPLE_PROPERTIES_TEMPLATE).result(binding)
48
68
  end
49
- function_body
50
69
  end
51
70
 
52
- def event_enum(enum, file_name)
71
+ def people_properties_enum
53
72
  # empty
54
73
  end
55
74
 
56
- def people_properties(people_bundle, file_name)
75
+ def special_property_enums(enums_bundle)
57
76
  header_footer_wrapper do
58
- props = "\tenum Property: String {\n"
59
- people_bundle.each do |prop|
60
- props << "\t\tcase #{camelize(prop)} = \"#{prop}\"\n"
77
+ enums = enums_bundle.map do |enum|
78
+ values = enum.values.map do |value|
79
+ {
80
+ case_name: camelize(value),
81
+ value: value
82
+ }
83
+ end
84
+
85
+ {
86
+ name: enum.enum_name,
87
+ values: values
88
+ }
61
89
  end
62
- props << "\t}"
90
+
91
+ template_from(SPECIAL_PROPERTY_ENUMS_TEMPLATE).result(binding)
63
92
  end
64
93
  end
65
94
 
66
- def special_property_enums(enums)
95
+ def destinations(destinations_bundle, _file_name)
67
96
  header_footer_wrapper do
68
- enums.map do |enum|
69
- body = "\tenum #{enum.enum_name}: String {\n"
70
- enum.values.each do |value|
71
- body << "\t\tcase #{camelize(value)} = \"#{value}\"\n"
72
- end
73
- body << "\t}"
74
- end.join("\n\n")
97
+ destinations = destinations_bundle.map { |p| camelize(p) }
98
+
99
+ template_from(DESTINATIONS_TEMPLATE).result(binding)
75
100
  end
76
101
  end
77
102
 
78
103
  private
79
104
 
80
105
  def header_footer_wrapper
81
- """// This file was automatically generated by evva: https://github.com/hole19/evva
82
-
83
- import Foundation
106
+ content = yield
107
+ .gsub(/^/, "\t").gsub(/^\t+$/, "") # add tabs, unless it's an empty line
108
+ .chop # trim trailing newlines created by sublime
84
109
 
85
- extension Analytics {
86
-
87
- #{yield.gsub("\t", " ")}
88
- }
89
- """
110
+ template_from(BASE_TEMPLATE).result(binding).gsub("\t", TAB_SIZE)
90
111
  end
91
112
 
92
- def dictionary_pairs(props)
93
- props.map do |name, type|
94
- pair = "\"#{name}\": #{name}"
95
- if is_raw_representable_property?(type)
96
- if is_optional_property?(type)
97
- pair += "?"
98
- end
99
- pair += ".rawValue"
100
- end
101
- pair += " as Any"
102
- end
103
- end
113
+ def template_from(path)
114
+ file = File.read(path)
104
115
 
105
- def is_raw_representable_property?(type)
106
- !NATIVE_TYPES.include?(native_type(type).chomp('?'))
107
- end
108
-
109
- def is_optional_property?(type)
110
- type.end_with?('?')
116
+ # - 2nd argument (nil) changes nothing
117
+ # - 3rd argument activates trim mode using "-" so that you can decide to
118
+ # not include a line (useful on loops and if statements)
119
+ ERB.new(file, nil, '-')
111
120
  end
112
121
 
113
122
  def native_type(type)
114
- type.gsub('Boolean','Bool').gsub('Long', 'Int')
123
+ type
124
+ .gsub('Boolean','Bool')
125
+ .gsub('Long', 'Int')
115
126
  end
116
127
 
117
- def prepend_let(props)
118
- props.map { |k, v| "let #{k}" }.join(', ')
128
+ def is_special_property?(type)
129
+ !NATIVE_TYPES.include?(type.chomp('?'))
119
130
  end
120
131
 
121
132
  def camelize(term)
@@ -125,6 +136,5 @@ extension Analytics {
125
136
  string.gsub!("/".freeze, "::".freeze)
126
137
  string
127
138
  end
128
-
129
139
  end
130
140
  end
@@ -0,0 +1,7 @@
1
+ package <%= package_name %>
2
+
3
+ /**
4
+ * This file was automatically generated by evva: https://github.com/hole19/evva
5
+ */
6
+
7
+ <%= content %>
@@ -0,0 +1,5 @@
1
+ enum class <%= class_name %> {
2
+ <%- destinations.each_with_index do |destination, index| -%>
3
+ <%= destination %><%= index == destinations.count - 1 ? ";" : "," %>
4
+ <%- end -%>
5
+ }
@@ -0,0 +1,5 @@
1
+ enum class <%= class_name %>(val key: String) {
2
+ <%- events.each_with_index do |event, index| -%>
3
+ <%= event[:name] %>("<%= event[:value] %>")<%= index == events.count - 1 ? ";" : "," %>
4
+ <%- end -%>
5
+ }
@@ -0,0 +1,34 @@
1
+ sealed class <%= class_name %>(event: <%= enums_class_name %>) {
2
+ val name = event.key
3
+
4
+ open val properties: Map<String, Any?>? = null
5
+ open val destinations: Array<<%= destinations_class_name %>> = []
6
+
7
+ <%- events.each_with_index do |e, index| -%>
8
+ <%- if e[:is_object] -%>
9
+ object <%= e[:class_name] %> : <%= class_name %>(<%= enums_class_name %>.<%= e[:event_name] %>)
10
+ <%- else -%>
11
+ data class <%= e[:class_name] %><% if e[:properties].count > 0 %>(
12
+ <%= e[:properties].map { |p| "val #{p[:param_name]}: #{p[:type]}" }.join(", ") %>
13
+ )<% end %> : <%= class_name %>(<%= enums_class_name %>.<%= e[:event_name] %>) {
14
+ <%- if e[:properties].count > 0 -%>
15
+ override val properties = mapOf(
16
+ <%- e[:properties].each_with_index do |p, index| -%>
17
+ "<%= p[:name] %>" to <%= p[:value_fetcher] %><% if index < e[:properties].count - 1 %>,<% end %>
18
+ <%- end -%>
19
+ )
20
+ <%- end -%>
21
+ <%- if e[:destinations].count > 0 -%>
22
+ override val destinations = [
23
+ <%- e[:destinations].each_with_index do |d, index| -%>
24
+ <%= destinations_class_name %>.<%= d %><% if index < e[:destinations].count - 1 %>,<% end %>
25
+ <%- end -%>
26
+ ]
27
+ <%- end -%>
28
+ }
29
+ <%- end -%>
30
+ <%- unless index == events.count - 1 -%>
31
+
32
+ <%- end -%>
33
+ <%- end -%>
34
+ }
@@ -0,0 +1,24 @@
1
+ sealed class <%= class_name %>(property: <%= enums_class_name %>) {
2
+ val name = property.key
3
+
4
+ open val value: Any = ""
5
+ open val destinations: Array<<%= destinations_class_name %>> = []
6
+
7
+ <%- properties.each_with_index do |property, index| -%>
8
+ data class <%= property[:class_name] %>(
9
+ val value: <%= property[:type] %>
10
+ ) : <%= class_name %>(<%= enums_class_name %>.<%= property[:property_name] %>) {
11
+ override val value = value<% if property[:is_special_property] %>.key<% end %>
12
+ <%- if property[:destinations].count > 0 -%>
13
+ override val destinations = [
14
+ <%- property[:destinations].each_with_index do |d, index| -%>
15
+ <%= destinations_class_name %>.<%= d %><% if index < property[:destinations].count - 1 %>,<% end %>
16
+ <%- end -%>
17
+ ]
18
+ <%- end -%>
19
+ }
20
+ <%- unless index == properties.count - 1 -%>
21
+
22
+ <%- end -%>
23
+ <%- end -%>
24
+ }
@@ -0,0 +1,5 @@
1
+ enum class <%= class_name %>(val key: String) {
2
+ <%- properties.each_with_index do |property, index| -%>
3
+ <%= property[:name] %>("<%= property[:value] %>")<%= index == properties.count - 1 ? ";" : "," %>
4
+ <%- end -%>
5
+ }
@@ -0,0 +1,10 @@
1
+ <%- enums.each_with_index do |enum, index| -%>
2
+ enum class <%= enum[:class_name] %>(val key: String) {
3
+ <%- enum[:values].each_with_index do |v, index| -%>
4
+ <%= v[:name] %>("<%= v[:value] %>")<%= index == enum[:values].count - 1 ? ";" : "," %>
5
+ <%- end -%>
6
+ }
7
+ <%- unless index == enums.count - 1 -%>
8
+
9
+ <%- end -%>
10
+ <%- end -%>
@@ -0,0 +1,7 @@
1
+ // This file was automatically generated by evva: https://github.com/hole19/evva
2
+
3
+ import Foundation
4
+
5
+ extension Analytics {
6
+ <%= content %>
7
+ }
@@ -0,0 +1,5 @@
1
+ enum Destination {
2
+ <%- destinations.each do |d| -%>
3
+ case <%= d %>
4
+ <%- end -%>
5
+ }
@@ -0,0 +1,65 @@
1
+ struct EventData {
2
+ let name: String
3
+ var properties: [String: Any]?
4
+ let destinations: [Destination]
5
+
6
+ init(name: String, properties: [String: Any]?, destinations: [Destination]) {
7
+ self.name = name
8
+ self.properties = properties
9
+ self.destinations = destinations
10
+ }
11
+
12
+ init(name: EventName, properties: [String: Any]?, destinations: [Destination]) {
13
+ self.init(name: name.rawValue, properties: properties, destinations: destinations)
14
+ }
15
+ }
16
+
17
+ enum EventName: String {
18
+ <%- events.each do |e| -%>
19
+ case <%= e[:case_name] %> = "<%= e[:event_name] %>"
20
+ <%- end -%>
21
+ }
22
+
23
+ enum Event {
24
+ <%- events.each do |e| -%>
25
+ <%- if e[:properties].count == 0 -%>
26
+ case <%= e[:case_name] %>
27
+ <%- else -%>
28
+ case <%= e[:case_name] %>(<%= e[:properties].map { |p| "#{p[:name]}: #{p[:type]}" }.join(", ") %>)
29
+ <%- end -%>
30
+ <%- end -%>
31
+
32
+ var data: EventData {
33
+ switch self {
34
+ <%- events.each_with_index do |e, index| -%>
35
+ <%- if e[:properties].count == 0 -%>
36
+ case .<%= e[:case_name] %>:
37
+ <%- else -%>
38
+ case let .<%= e[:case_name] %>(<%= e[:properties].map { |p| p[:name] }.join(", ") %>):
39
+ <%- end -%>
40
+ return EventData(name: .<%= e[:case_name] %>,
41
+ <%- if e[:properties].count == 0 -%>
42
+ properties: nil,
43
+ <%- else -%>
44
+ properties: [
45
+ <%- e[:properties].each do |p| -%>
46
+ "<%= p[:name] %>": <%= p[:value] %> as Any,
47
+ <%- end -%>
48
+ ],
49
+ <%- end -%>
50
+ <%- if e[:destinations].count == 0 -%>
51
+ destinations: [])
52
+ <%- else -%>
53
+ destinations: [
54
+ <%- e[:destinations].each do |d| -%>
55
+ .<%= d %>,
56
+ <%- end -%>
57
+ ])
58
+ <%- end -%>
59
+ <%- unless index == events.count - 1 -%>
60
+
61
+ <%- end -%>
62
+ <%- end -%>
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,49 @@
1
+ struct PropertyData {
2
+ let name: String
3
+ let value: Any
4
+ let destinations: [Destination]
5
+
6
+ init(name: String, value: Any, destinations: [Destination]) {
7
+ self.name = name
8
+ self.value = value
9
+ self.destinations = destinations
10
+ }
11
+
12
+ init(name: PropertyName, value: Any, destinations: [Destination]) {
13
+ self.init(name: name.rawValue, value: value, destinations: destinations)
14
+ }
15
+ }
16
+
17
+ enum PropertyName: String {
18
+ <%- properties.each do |p| -%>
19
+ case <%= p[:case_name] %> = "<%= p[:property_name ] %>"
20
+ <%- end -%>
21
+ }
22
+
23
+ enum Property {
24
+ <%- properties.each do |p| -%>
25
+ case <%= p[:case_name] %>(<%= p[:type] %>)
26
+ <%- end -%>
27
+
28
+ var data: PropertyData {
29
+ switch self {
30
+ <%- properties.each_with_index do |p, index| -%>
31
+ case let .<%= p[:case_name] %>(value):
32
+ return PropertyData(name: .<%= p[:case_name] %>,
33
+ value: value<% if p[:is_special_property] %>.rawValue<% end %>,
34
+ <%- if p[:destinations].count == 0 -%>
35
+ destinations: [])
36
+ <%- else -%>
37
+ destinations: [
38
+ <%- p[:destinations].each do |d| -%>
39
+ .<%= d %>,
40
+ <%- end -%>
41
+ ])
42
+ <%- end -%>
43
+ <%- unless index == properties.count - 1 -%>
44
+
45
+ <%- end -%>
46
+ <%- end -%>
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,10 @@
1
+ <%- enums.each_with_index do |enum, index| -%>
2
+ enum <%= enum[:name] %>: String {
3
+ <%- enum[:values].each do |v| -%>
4
+ case <%= v[:case_name] %> = "<%= v[:value ] %>"
5
+ <%- end -%>
6
+ }
7
+ <%- unless index == enums.count - 1 -%>
8
+
9
+ <%- end -%>
10
+ <%- end -%>
data/lib/evva/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Evva
2
- VERSION = '0.3.0'.freeze
3
- VERSION_UPDATED_AT = '2021-12-16'.freeze
2
+ VERSION = '0.4.0'.freeze
3
+ VERSION_UPDATED_AT = '2021-12-21'.freeze
4
4
  end
data/lib/evva.rb CHANGED
@@ -7,6 +7,7 @@ require 'evva/config'
7
7
  require 'evva/file_reader'
8
8
  require 'evva/analytics_event'
9
9
  require 'evva/analytics_enum'
10
+ require 'evva/analytics_property'
10
11
  require 'evva/object_extension'
11
12
  require 'evva/version'
12
13
  require 'evva/android_generator'
@@ -37,7 +38,7 @@ module Evva
37
38
 
38
39
  def evva_write(bundle, generator, configuration, extension)
39
40
  path = "#{configuration.out_path}/#{configuration.event_file_name}.#{extension}"
40
- write_to_file(path, generator.events(bundle[:events], configuration.event_file_name))
41
+ write_to_file(path, generator.events(bundle[:events], configuration.event_file_name, configuration.event_enum_file_name, configuration.destinations_file_name))
41
42
 
42
43
  unless configuration.type.downcase == 'ios'
43
44
  path = "#{configuration.out_path}/#{configuration.event_enum_file_name}.#{extension}"
@@ -45,10 +46,18 @@ module Evva
45
46
  end
46
47
 
47
48
  path = "#{configuration.out_path}/#{configuration.people_file_name}.#{extension}"
48
- write_to_file(path, generator.people_properties(bundle[:people], configuration.people_file_name))
49
+ write_to_file(path, generator.people_properties(bundle[:people], configuration.people_file_name, configuration.people_enum_file_name, configuration.destinations_file_name))
50
+
51
+ unless configuration.type.downcase == 'ios'
52
+ path = "#{configuration.out_path}/#{configuration.people_enum_file_name}.#{extension}"
53
+ write_to_file(path, generator.people_properties_enum(bundle[:people], configuration.people_enum_file_name))
54
+ end
49
55
 
50
56
  path = "#{configuration.out_path}/#{configuration.special_enum_file_name}.#{extension}"
51
57
  write_to_file(path, generator.special_property_enums(bundle[:enums]))
58
+
59
+ path = "#{configuration.out_path}/#{configuration.destinations_file_name}.#{extension}"
60
+ write_to_file(path, generator.destinations(bundle[:destinations], configuration.destinations_file_name))
52
61
  end
53
62
 
54
63
  def analytics_data(config:)
@@ -61,6 +70,7 @@ module Evva
61
70
  events_bundle[:events] = source.events
62
71
  events_bundle[:people] = source.people_properties
63
72
  events_bundle[:enums] = source.enum_classes
73
+ events_bundle[:destinations] = source.destinations
64
74
  events_bundle
65
75
  end
66
76
 
data/spec/evva_spec.rb CHANGED
@@ -6,12 +6,10 @@ describe Evva do
6
6
 
7
7
  before do
8
8
  allow_any_instance_of(Evva::FileReader).to receive(:open_file).and_return(file)
9
- allow_any_instance_of(Evva::GoogleSheet).to receive(:events).and_return(
10
- [Evva::AnalyticsEvent.new('trackEvent',[])])
11
-
9
+ allow_any_instance_of(Evva::GoogleSheet).to receive(:events).and_return([])
12
10
  allow_any_instance_of(Evva::GoogleSheet).to receive(:people_properties).and_return([])
13
11
  allow_any_instance_of(Evva::GoogleSheet).to receive(:enum_classes).and_return([])
14
-
12
+ allow_any_instance_of(Evva::GoogleSheet).to receive(:destinations).and_return([])
15
13
  allow(Evva).to receive(:write_to_file)
16
14
  end
17
15
 
@@ -37,4 +35,4 @@ describe Evva do
37
35
  .and change { Evva::Logger.summary[:error] }.by(1)
38
36
  end
39
37
  end
40
- end
38
+ end
@@ -1,4 +1,4 @@
1
- Event Name,Event Properties
2
- cp_page_view,"course_id:Long,course_name:String"
3
- nav_feed_tap,
4
- cp_view_scorecard,"course_id:Long,course_name:String"
1
+ Event Name,Event Properties,Event Destination
2
+ cp_page_view,"course_id:Long,course_name:String","firebase,custom destination"
3
+ nav_feed_tap,,
4
+ cp_view_scorecard,"course_id:Long,course_name:String","custom destination"
@@ -1,3 +1,4 @@
1
- Property Name,Comments
2
- rounds_with_wear,asldkaslkdlaksd
3
- total_friends,
1
+ Property Name,Property Type,Property Destination
2
+ rounds_with_wear,String,"firebase,custom destination"
3
+ total_friends,Int,
4
+ wearable_platform,WearableAppPlatform,firebase
@@ -9,5 +9,7 @@ data_source:
9
9
  out_path: analytics
10
10
  event_file_name: AnalyticsEvent
11
11
  event_enum_file_name: AnalyticsEvents
12
- people_file_name: AnalyticsProperties
12
+ people_file_name: AnalyticsProperty
13
+ people_enum_file_name: AnalyticsProperties
14
+ destinations_file_name: AnalyticsDestinations
13
15
  package_name: com.package.name.analytics