evva 0.1.4.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,29 +10,26 @@ module Evva
10
10
  NATIVE_TYPES = %w[Int String Double Float Bool].freeze
11
11
 
12
12
  def events(bundle, file_name)
13
- event_file = EXTENSION_HEADER
14
- event_file += "\tenum Event {\n\n"
15
- bundle.each do |event|
16
- event_file += event_case(event)
13
+ 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
23
  end
18
- event_file += "\n\t\tvar data: EventData {\n"
19
- event_file += "\t\t\tswitch self {\n"
20
- bundle.each do |event|
21
- event_file += event_data(event)
22
- end
23
- event_file += "\t\t\t}\n"
24
- event_file += "\t\t}\n\n"
25
- event_file += "\t}"
26
- event_file += EXTENSION_FOOTER
27
24
  end
28
25
 
29
26
  def event_case(event_data)
30
27
  function_name = camelize(event_data.event_name)
31
28
  if event_data.properties.empty?
32
- "\t\tcase #{function_name}\n"
29
+ "\t\tcase #{function_name}"
33
30
  else
34
31
  trimmed_properties = event_data.properties.map { |k, v| k.to_s + ': ' + native_type(v) }.join(", ")
35
- "\t\tcase #{function_name}(#{trimmed_properties})\n"
32
+ "\t\tcase #{function_name}(#{trimmed_properties})"
36
33
  end
37
34
  end
38
35
 
@@ -40,14 +37,14 @@ module Evva
40
37
  function_name = camelize(event_data.event_name)
41
38
  if event_data.properties.empty?
42
39
  function_body = "\t\t\tcase .#{function_name}:\n" \
43
- "\t\t\t\treturn EventData(name: \"#{event_data.event_name}\")\n\n"
40
+ "\t\t\t\treturn EventData(name: \"#{event_data.event_name}\")"
44
41
  else
45
42
  function_header = prepend_let(event_data.properties)
46
43
  function_arguments = dictionary_pairs(event_data.properties)
47
44
  function_body = "\t\t\tcase .#{function_name}(#{function_header}):\n"\
48
45
  "\t\t\t\treturn EventData(name: \"#{event_data.event_name}\", properties: [\n"\
49
46
  "\t\t\t\t\t#{function_arguments.join(",\n\t\t\t\t\t")} ]\n"\
50
- "\t\t\t\t)\n\n"
47
+ "\t\t\t\t)"
51
48
  end
52
49
  function_body
53
50
  end
@@ -57,23 +54,39 @@ module Evva
57
54
  end
58
55
 
59
56
  def people_properties(people_bundle, file_name)
60
- properties = EXTENSION_HEADER
61
- properties += "\tenum Property: String {\n"
62
- people_bundle.each do |prop|
63
- properties += "\t\tcase #{camelize(prop)} = \"#{prop}\"\n"
57
+ header_footer_wrapper do
58
+ props = "\tenum Property: String {\n"
59
+ people_bundle.each do |prop|
60
+ props << "\t\tcase #{camelize(prop)} = \"#{prop}\"\n"
61
+ end
62
+ props << "\t}"
64
63
  end
65
- properties += "\t}"
66
- properties += EXTENSION_FOOTER
67
64
  end
68
65
 
69
- def special_property_enum(enum)
70
- enum_body = EXTENSION_HEADER
71
- enum_body += "\tenum #{enum.enum_name}: String {\n"
72
- enum.values.map do |val|
73
- enum_body += "\t\tcase #{val.tr(' ', '_')} = \"#{val}\"\n"
66
+ def special_property_enums(enums)
67
+ 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")
74
75
  end
75
- enum_body += "\t}"
76
- enum_body += EXTENSION_FOOTER
76
+ end
77
+
78
+ private
79
+
80
+ def header_footer_wrapper
81
+ """// This file was automatically generated by evva: https://github.com/hole19/evva
82
+
83
+ import Foundation
84
+
85
+ extension Analytics {
86
+
87
+ #{yield.gsub("\t", " ")}
88
+ }
89
+ """
77
90
  end
78
91
 
79
92
  def dictionary_pairs(props)
@@ -89,8 +102,6 @@ module Evva
89
102
  end
90
103
  end
91
104
 
92
- private
93
-
94
105
  def is_raw_representable_property?(type)
95
106
  !NATIVE_TYPES.include?(native_type(type).chomp('?'))
96
107
  end
@@ -108,7 +119,7 @@ module Evva
108
119
  end
109
120
 
110
121
  def camelize(term)
111
- string = term.to_s
122
+ string = term.to_s.tr(' ', '_').downcase
112
123
  string = string.sub(/^(?:#{@acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
113
124
  string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
114
125
  string.gsub!("/".freeze, "::".freeze)
data/lib/evva/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Evva
2
- VERSION = '0.1.4.2'.freeze
3
- VERSION_UPDATED_AT = '2018-02-14'.freeze
2
+ VERSION = '0.3.0'.freeze
3
+ VERSION_UPDATED_AT = '2021-12-16'.freeze
4
4
  end
data/lib/evva.rb CHANGED
@@ -5,9 +5,8 @@ require 'evva/logger'
5
5
  require 'evva/google_sheet'
6
6
  require 'evva/config'
7
7
  require 'evva/file_reader'
8
- require 'evva/data_source'
9
- require 'evva/mixpanel_event'
10
- require 'evva/mixpanel_enum'
8
+ require 'evva/analytics_event'
9
+ require 'evva/analytics_enum'
11
10
  require 'evva/object_extension'
12
11
  require 'evva/version'
13
12
  require 'evva/android_generator'
@@ -27,7 +26,7 @@ module Evva
27
26
  bundle = analytics_data(config: config.data_source)
28
27
  case config.type.downcase
29
28
  when 'android'
30
- generator = Evva::AndroidGenerator.new
29
+ generator = Evva::AndroidGenerator.new(config.package_name)
31
30
  evva_write(bundle, generator, config, 'kt')
32
31
  when 'ios'
33
32
  generator = Evva::SwiftGenerator.new
@@ -44,20 +43,19 @@ module Evva
44
43
  path = "#{configuration.out_path}/#{configuration.event_enum_file_name}.#{extension}"
45
44
  write_to_file(path, generator.event_enum(bundle[:events], configuration.event_enum_file_name))
46
45
  end
46
+
47
47
  path = "#{configuration.out_path}/#{configuration.people_file_name}.#{extension}"
48
48
  write_to_file(path, generator.people_properties(bundle[:people], configuration.people_file_name))
49
49
 
50
- bundle[:enums].each do |enum|
51
- path = "#{configuration.out_path}/#{enum.enum_name}.#{extension}"
52
- write_to_file(path, generator.special_property_enum(enum))
53
- end
50
+ path = "#{configuration.out_path}/#{configuration.special_enum_file_name}.#{extension}"
51
+ write_to_file(path, generator.special_property_enums(bundle[:enums]))
54
52
  end
55
53
 
56
54
  def analytics_data(config:)
57
55
  source =
58
56
  case config[:type]
59
57
  when 'google_sheet'
60
- Evva::GoogleSheet.new(config[:sheet_id])
58
+ Evva::GoogleSheet.new(config[:events_url], config[:people_properties_url], config[:enum_classes_url])
61
59
  end
62
60
  events_bundle = {}
63
61
  events_bundle[:events] = source.events
data/spec/evva_spec.rb CHANGED
@@ -7,7 +7,7 @@ describe Evva do
7
7
  before do
8
8
  allow_any_instance_of(Evva::FileReader).to receive(:open_file).and_return(file)
9
9
  allow_any_instance_of(Evva::GoogleSheet).to receive(:events).and_return(
10
- [Evva::MixpanelEvent.new('trackEvent',[])])
10
+ [Evva::AnalyticsEvent.new('trackEvent',[])])
11
11
 
12
12
  allow_any_instance_of(Evva::GoogleSheet).to receive(:people_properties).and_return([])
13
13
  allow_any_instance_of(Evva::GoogleSheet).to receive(:enum_classes).and_return([])
@@ -0,0 +1,3 @@
1
+ Enum Name,Possible Values
2
+ PageViewSourceScreen,"course_discovery,synced_courses,nearby,deal"
3
+ PremiumClickBuy,"notes,hi_res_maps,whatever"
@@ -0,0 +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"
@@ -0,0 +1,3 @@
1
+ Property Name,Comments
2
+ rounds_with_wear,asldkaslkdlaksd
3
+ total_friends,
@@ -2,9 +2,12 @@ type: Android
2
2
 
3
3
  data_source:
4
4
  type: google_sheet
5
- sheet_id: 1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4
5
+ events_url: https://path-to-csv
6
+ people_properties_url: https://path-to-csv
7
+ enum_classes_url: https://path-to-csv
6
8
 
7
9
  out_path: analytics
8
- event_file_name: MixpanelAnalytics
9
- event_enum_file_name: MixpanelEvent
10
- people_file_name: MixpanelProperties
10
+ event_file_name: AnalyticsEvent
11
+ event_enum_file_name: AnalyticsEvents
12
+ people_file_name: AnalyticsProperties
13
+ package_name: com.package.name.analytics
@@ -1,135 +1,144 @@
1
1
  describe Evva::AndroidGenerator do
2
- let(:generator) { described_class.new }
2
+ let(:generator) { described_class.new("com.hole19golf.hole19.analytics") }
3
3
 
4
- def trim_spaces(str)
5
- str.gsub(/^[ \t]+/, '')
6
- .gsub(/[ \t]+$/, '')
7
- end
4
+ describe '#events' do
5
+ subject { generator.events(events, "AnalyticsEvent") }
6
+
7
+ let(:events) { [
8
+ Evva::AnalyticsEvent.new('cp_page_view'),
9
+ Evva::AnalyticsEvent.new('cp_page_view_a', { course_id: 'Long', course_name: 'String' }),
10
+ Evva::AnalyticsEvent.new('cp_page_view_b', { course_id: 'Long', course_name: 'String', from_screen: 'CourseProfileSource' }),
11
+ Evva::AnalyticsEvent.new('cp_page_view_c', { course_id: 'Long', course_name: 'String', from_screen: 'CourseProfileSource?' }),
12
+ Evva::AnalyticsEvent.new('cp_page_view_d', { course_id: 'Long?', course_name: 'String' })
13
+ ] }
14
+
15
+ let(:expected) {
16
+ <<-Kotlin
17
+ package com.hole19golf.hole19.analytics
18
+
19
+ /**
20
+ * This file was automatically generated by evva: https://github.com/hole19/evva
21
+ */
22
+
23
+ sealed class AnalyticsEvent(event: AnalyticsEvents) {
24
+ val name = event.key
25
+
26
+ open val properties: Map<String, Any?>? = null
8
27
 
9
- describe '#kotlin_function' do
10
- subject { trim_spaces(generator.kotlin_function(event)) }
11
-
12
- context 'when the event has no properties' do
13
- let(:event) { Evva::MixpanelEvent.new('nav_feed_tap') }
14
- let(:expected) { <<-Kotlin
15
- open fun trackNavFeedTap() {
16
- mixpanelMask.trackEvent(MixpanelEvent.NAV_FEED_TAP)
17
- }
18
- Kotlin
19
- }
20
- it { should eq trim_spaces(expected) }
21
- end
22
-
23
- context 'event has properties' do
24
- let(:event) { Evva::MixpanelEvent.new('cp_page_view', { course_id: 'Long', course_name: 'String' }) }
25
- let(:expected) { <<-Kotlin
26
- open fun trackCpPageView(course_id: Long, course_name: String) {
27
- val properties = JSONObject().apply {
28
- put("course_id", course_id)
29
- put("course_name", course_name)
30
- }
31
- mixpanelMask.trackEvent(MixpanelEvent.CP_PAGE_VIEW, properties)
32
- }
33
- Kotlin
34
- }
35
- it { should eq trim_spaces(expected) }
36
- end
37
-
38
- context 'event has special properties' do
39
- let(:event) { Evva::MixpanelEvent.new('cp_page_view', { course_id: 'Long', course_name: 'String', from_screen: 'CourseProfileSource' }) }
40
- let(:expected) { <<-Kotlin
41
- open fun trackCpPageView(course_id: Long, course_name: String, from_screen: CourseProfileSource) {
42
- val properties = JSONObject().apply {
43
- put("course_id", course_id)
44
- put("course_name", course_name)
45
- put("from_screen", from_screen.key)
46
- }
47
- mixpanelMask.trackEvent(MixpanelEvent.CP_PAGE_VIEW, properties)
48
- }
49
- Kotlin
50
- }
51
- it { should eq trim_spaces(expected) }
52
- end
53
-
54
- context 'event has optional properties' do
55
- let(:event) { Evva::MixpanelEvent.new('cp_page_view', { course_id: 'Long', course_name: 'String', from_screen: 'CourseProfileSource?' }) }
56
- let(:expected) { <<-Kotlin
57
- open fun trackCpPageView(course_id: Long, course_name: String, from_screen: CourseProfileSource?) {
58
- val properties = JSONObject().apply {
59
- put("course_id", course_id)
60
- put("course_name", course_name)
61
- from_screen?.let { put("from_screen", it.key) }
62
- }
63
- mixpanelMask.trackEvent(MixpanelEvent.CP_PAGE_VIEW, properties)
64
- }
65
- Kotlin
66
- }
67
- it { should eq trim_spaces(expected) }
68
- end
69
-
70
- context 'event has optional but not special properties' do
71
- let(:event) { Evva::MixpanelEvent.new('cp_page_view', { course_id: 'Long?', course_name: 'String' }) }
72
- let(:expected) { <<-Kotlin
73
- open fun trackCpPageView(course_id: Long?, course_name: String) {
74
- val properties = JSONObject().apply {
75
- course_id?.let { put("course_id", it) }
76
- put("course_name", course_name)
77
- }
78
- mixpanelMask.trackEvent(MixpanelEvent.CP_PAGE_VIEW, properties)
79
- }
80
- Kotlin
81
- }
82
- it { should eq trim_spaces(expected) }
83
- end
28
+ object CpPageView : AnalyticsEvent(AnalyticsEvents.CP_PAGE_VIEW)
29
+
30
+ data class CpPageViewA(
31
+ val courseId: Long, val courseName: String
32
+ ) : AnalyticsEvent(AnalyticsEvents.CP_PAGE_VIEW_A) {
33
+ override val properties = mapOf(
34
+ "course_id" to courseId,
35
+ "course_name" to courseName
36
+ )
37
+ }
38
+
39
+ data class CpPageViewB(
40
+ val courseId: Long, val courseName: String, val fromScreen: CourseProfileSource
41
+ ) : AnalyticsEvent(AnalyticsEvents.CP_PAGE_VIEW_B) {
42
+ override val properties = mapOf(
43
+ "course_id" to courseId,
44
+ "course_name" to courseName,
45
+ "from_screen" to fromScreen.key
46
+ )
47
+ }
48
+
49
+ data class CpPageViewC(
50
+ val courseId: Long, val courseName: String, val fromScreen: CourseProfileSource?
51
+ ) : AnalyticsEvent(AnalyticsEvents.CP_PAGE_VIEW_C) {
52
+ override val properties = mapOf(
53
+ "course_id" to courseId,
54
+ "course_name" to courseName,
55
+ "from_screen" to fromScreen?.key
56
+ )
57
+ }
58
+
59
+ data class CpPageViewD(
60
+ val courseId: Long?, val courseName: String
61
+ ) : AnalyticsEvent(AnalyticsEvents.CP_PAGE_VIEW_D) {
62
+ override val properties = mapOf(
63
+ "course_id" to courseId,
64
+ "course_name" to courseName
65
+ )
66
+ }
67
+ }
68
+ Kotlin
69
+ }
70
+
71
+ it { should eq expected }
84
72
  end
85
73
 
86
- describe '#special_property_enum' do
87
- subject { trim_spaces(generator.special_property_enum(enum)) }
88
- let(:enum) { Evva::MixpanelEnum.new('CourseProfileSource', ['course_discovery','synced_courses']) }
89
- let(:expected) { <<-Kotlin
90
- package com.hole19golf.hole19.analytics
91
-
92
- enum class CourseProfileSource(val key: String) {
93
- COURSE_DISCOVERY("course_discovery"),
94
- SYNCED_COURSES("synced_courses")
95
- }
96
- Kotlin
74
+ describe '#special_property_enums' do
75
+ subject { generator.special_property_enums(enums) }
76
+ let(:enums) { [
77
+ Evva::AnalyticsEnum.new('CourseProfileSource', ['course_discovery', 'synced_courses']),
78
+ Evva::AnalyticsEnum.new('PremiumFrom', ['Course Profile', 'Round Setup'])
79
+ ] }
80
+ let(:expected) {
81
+ <<-Kotlin
82
+ package com.hole19golf.hole19.analytics
83
+
84
+ /**
85
+ * This file was automatically generated by evva: https://github.com/hole19/evva
86
+ */
87
+
88
+ enum class CourseProfileSource(val key: String) {
89
+ COURSE_DISCOVERY("course_discovery"),
90
+ SYNCED_COURSES("synced_courses");
91
+ }
92
+
93
+ enum class PremiumFrom(val key: String) {
94
+ COURSE_PROFILE("Course Profile"),
95
+ ROUND_SETUP("Round Setup");
96
+ }
97
+ Kotlin
97
98
  }
98
- it { should eq trim_spaces(expected) }
99
+ it { should eq expected }
99
100
  end
100
101
 
101
102
  describe '#event_enum' do
102
- subject { trim_spaces(generator.event_enum(event_bundle, 'MixpanelEvent')) }
103
+ subject { generator.event_enum(event_bundle, 'AnalyticsEvents') }
103
104
  let(:event_bundle) { [
104
- Evva::MixpanelEvent.new('nav_feed_tap', {}),
105
- Evva::MixpanelEvent.new('nav_performance_tap', {})
105
+ Evva::AnalyticsEvent.new('nav_feed_tap', {}),
106
+ Evva::AnalyticsEvent.new('nav_performance_tap', {})
106
107
  ] }
107
- let(:expected) { <<-Kotlin
108
- package com.hole19golf.hole19.analytics
109
- import com.hole19golf.hole19.analytics.Event
110
-
111
- enum class MixpanelEvent(override val key: String) : Event {
112
- NAV_FEED_TAP("nav_feed_tap"),
113
- NAV_PERFORMANCE_TAP("nav_performance_tap")
114
- }
115
- Kotlin
108
+ let(:expected) {
109
+ <<-Kotlin
110
+ package com.hole19golf.hole19.analytics
111
+
112
+ /**
113
+ * This file was automatically generated by evva: https://github.com/hole19/evva
114
+ */
115
+
116
+ enum class AnalyticsEvents(val key: String) {
117
+ NAV_FEED_TAP("nav_feed_tap"),
118
+ NAV_PERFORMANCE_TAP("nav_performance_tap");
119
+ }
120
+ Kotlin
116
121
  }
117
- it { should eq trim_spaces(expected) }
122
+ it { should eq expected }
118
123
  end
119
124
 
120
125
  describe '#people_properties' do
121
- subject { trim_spaces(generator.people_properties(people_bundle, 'MixpanelProperties')) }
126
+ subject { generator.people_properties(people_bundle, 'AnalyticsProperties') }
122
127
  let(:people_bundle) { ['rounds_with_wear', 'friends_from_facebook'] }
123
- let(:expected) { <<-Kotlin
124
- package com.hole19golf.hole19.analytics
125
- import com.hole19golf.hole19.analytics.Event
126
-
127
- enum class MixpanelProperties(val key: String) {
128
- ROUNDS_WITH_WEAR("rounds_with_wear"),
129
- FRIENDS_FROM_FACEBOOK("friends_from_facebook");
130
- }
131
- Kotlin
128
+ let(:expected) {
129
+ <<-Kotlin
130
+ package com.hole19golf.hole19.analytics
131
+
132
+ /**
133
+ * This file was automatically generated by evva: https://github.com/hole19/evva
134
+ */
135
+
136
+ enum class AnalyticsProperties(val key: String) {
137
+ ROUNDS_WITH_WEAR("rounds_with_wear"),
138
+ FRIENDS_FROM_FACEBOOK("friends_from_facebook");
139
+ }
140
+ Kotlin
132
141
  }
133
- it { should eq trim_spaces(expected) }
142
+ it { should eq expected }
134
143
  end
135
144
  end
@@ -5,13 +5,16 @@ describe Evva::Config do
5
5
  {
6
6
  type: 'EvvaOS',
7
7
  data_source: {
8
- type: 'google_sheet',
9
- sheet_id: 'abc1234567890'
8
+ type: 'google_sheet',
9
+ events_url: 'https://events.csv',
10
+ people_properties_url: 'https://people_properties.csv',
11
+ enum_classes_url: 'https://enum_classes.csv',
10
12
  },
11
13
  out_path: 'clear/path/to/event',
12
14
  event_file_name: 'event/file/name',
13
15
  people_file_name: 'people/file/name',
14
- event_enum_file_name: 'event/enum/file'
16
+ event_enum_file_name: 'event/enum/file',
17
+ package_name: 'com.package.name.analytics'
15
18
  }
16
19
  end
17
20
 
@@ -26,11 +29,12 @@ describe Evva::Config do
26
29
  its(:event_file_name) { should eq('event/file/name') }
27
30
  its(:people_file_name) { should eq('people/file/name') }
28
31
  its(:event_enum_file_name) { should eq 'event/enum/file' }
32
+ its(:package_name) { should eq 'com.package.name.analytics' }
29
33
 
30
34
  describe '#data_source' do
31
35
  subject(:data_source) { config.data_source }
32
36
 
33
- it { should eq(type: 'google_sheet', sheet_id: 'abc1234567890') }
37
+ it { should eq(type: 'google_sheet', events_url: 'https://events.csv', people_properties_url: 'https://people_properties.csv', enum_classes_url: 'https://enum_classes.csv') }
34
38
 
35
39
  context 'when given an unknown type data source' do
36
40
  before { hash[:data_source] = { type: 'i_dunno' } }