evva 0.1.4.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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' } }