evva 0.1.4.1 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: eb97d0f1d8232f0bd8be466a5bb44d0d6969d620
4
- data.tar.gz: eafd1e8f81baa14886ba4fcb466ea18b59f9b199
2
+ SHA256:
3
+ metadata.gz: c9078e38ca6bba5b85a3349fb9e1c3f9c31b8de357080ffb1ab105e6bcbbdaa1
4
+ data.tar.gz: 16b264637125fafdc14a991a9cb984e440b948bdc7d934776329b8aa8ef2d89f
5
5
  SHA512:
6
- metadata.gz: 6f35827bcadcc08b17693f45d7b5106c75fddb277df50f837eb38e8ab10e06612d53ee550a37ad173e85ffa9e830a5b4debb2136c361dff0e4335c15054449b7
7
- data.tar.gz: eec447eb9229129b08415d30382e23fcab70b354a6512e906d756fe7c87ef734011fe2ba4da7cc09706ac00bcd2310e6047698f36e5eaafcb3be2d9521b9ef0d
6
+ metadata.gz: 6efc1abd4ea8d72f7ac2edeccbf111deac25922fa0b1464d754d21e7bfef921efffddd228bb6d6913f3b64a4acfcd8763082f0b36b16e85e28b930d933df879c
7
+ data.tar.gz: 77a4ad5df7074b646def8c880654b551fcde2e10523e3dec622d202fba48ac7bdda6d1a882abcd5c54bc2e6175b2bb68a52c30ab77d1c522f29362bc9a297db3
data/.gitignore CHANGED
@@ -1,6 +1,5 @@
1
1
  *.sublime-*
2
- .ruby-version
3
2
  running
4
3
  coverage
5
4
  .DS_Store*
6
- .byebug_history
5
+ .byebug_history
data/.rspec CHANGED
@@ -1,5 +1,4 @@
1
1
  --color
2
2
  --format documentation
3
3
  --profile
4
- --drb
5
4
  --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.3
data/.travis.yml ADDED
@@ -0,0 +1 @@
1
+ language: ruby
data/Gemfile CHANGED
@@ -1,13 +1,15 @@
1
1
  source 'https://rubygems.org'
2
- ruby '2.3.3'
2
+ ruby '2.7.3'
3
3
 
4
4
  gem 'colorize'
5
- gem 'rubocop'
6
5
  gem 'safe_yaml'
7
- gem 'xml-simple'
8
6
 
9
- gem 'rspec'
10
- gem 'rspec-its'
11
- gem 'simplecov', require: false, group: :test
12
- gem 'simplecov-rcov', require: false
13
- gem 'webmock', '~> 1.20'
7
+ group :test do
8
+ gem 'rake'
9
+ gem 'rspec'
10
+ gem 'rspec-its'
11
+ gem 'simplecov', require: false, group: :test
12
+ gem 'simplecov-rcov', require: false
13
+ gem 'webmock', '~> 1.20'
14
+ gem 'rubocop'
15
+ end
data/Gemfile.lock CHANGED
@@ -10,7 +10,7 @@ GEM
10
10
  diff-lcs (1.3)
11
11
  docile (1.1.5)
12
12
  hashdiff (0.3.7)
13
- json (2.1.0)
13
+ json (2.3.0)
14
14
  parallel (1.12.0)
15
15
  parser (2.4.0.0)
16
16
  ast (~> 2.2)
@@ -18,7 +18,7 @@ GEM
18
18
  public_suffix (3.0.0)
19
19
  rainbow (2.2.2)
20
20
  rake
21
- rake (12.1.0)
21
+ rake (12.3.3)
22
22
  rspec (3.7.0)
23
23
  rspec-core (~> 3.7.0)
24
24
  rspec-expectations (~> 3.7.0)
@@ -56,13 +56,13 @@ GEM
56
56
  addressable (>= 2.3.6)
57
57
  crack (>= 0.3.2)
58
58
  hashdiff
59
- xml-simple (1.1.5)
60
59
 
61
60
  PLATFORMS
62
61
  ruby
63
62
 
64
63
  DEPENDENCIES
65
64
  colorize
65
+ rake
66
66
  rspec
67
67
  rspec-its
68
68
  rubocop
@@ -70,10 +70,9 @@ DEPENDENCIES
70
70
  simplecov
71
71
  simplecov-rcov
72
72
  webmock (~> 1.20)
73
- xml-simple
74
73
 
75
74
  RUBY VERSION
76
- ruby 2.3.3p222
75
+ ruby 2.7.3p183
77
76
 
78
77
  BUNDLED WITH
79
- 1.15.4
78
+ 2.2.26
data/README.md CHANGED
@@ -1,4 +1,10 @@
1
1
  Evva
2
+ ========
3
+
4
+ [![Status](https://travis-ci.org/hole19/evva.svg?branch=master)](https://travis-ci.org/hole19/evva?branch=master)
5
+ [![Gem](https://img.shields.io/gem/v/evva.svg?style=flat)](http://rubygems.org/gems/evva "View this project in Rubygems")
6
+
7
+ Evva automatically generates code for triggering events based on a Google Sheets specification. It generated code for both iOS (Swift) and Android (Kotlin).
2
8
 
3
9
  # Instalation
4
10
 
@@ -19,9 +25,13 @@ Evva
19
25
  data_source:
20
26
  type: google_sheet
21
27
  sheet_id: <GOOGLE-DRIVE-SHEET-ID>
28
+ events_url: <GOOGLE-DRIVE-EVENTS-SHEET-URL>
29
+ people_properties_url: <GOOGLE-DRIVE-PEOPLE-PROPERTIES-SHEET-URL>
30
+ enum_classes_url: <GOOGLE-DRIVE-ENUM-CLASSES-SHEET-URL>
22
31
 
23
32
  out_path: /folder/where/analytics/classes/are
24
33
  event_file_name: /file/with/tracking/functions
25
34
  event_enum_file_name: /file/with/event/names
26
35
  people_file_name: /file/with/people/properties
36
+ special_enum_file_name: //file/with/special/enum/properties/
27
37
  ```
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "rake"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |t|
5
+ t.pattern = Dir.glob("spec/**/*_spec.rb")
6
+ t.rspec_opts = "--format documentation"
7
+ end
8
+
9
+ task default: :spec
data/changelog.md CHANGED
@@ -1,4 +1,20 @@
1
1
  # Change Log
2
+
3
+ ## [0.2.0] - 2021/08/30
4
+ - Google Spreadsheet option stopped working due to a change in the API. This version fixes that.
5
+
6
+ Note: You'll need a new setup. View README.
7
+
8
+ ## [0.1.4.4] - 2019-02-04
9
+ - Adds support for dynamic android package name
10
+
11
+ ## [0.1.4.3] - 2018-10-12
12
+ - Fixes swift and kotlin tabs, indentation and property names
13
+ - Merges all special enums in a single file
14
+
15
+ ## [0.1.4.2] - 2018-02-14
16
+ - Replaces Swift headers
17
+
2
18
  ## [0.1.4.1] - 2018-02-08
3
19
  - DRYs methods in swift event generation
4
20
 
@@ -17,4 +33,5 @@
17
33
  - Fixes mismatch between file name and class name generated.
18
34
 
19
35
  ## [0.1.0] - 2017/10/26
20
- - Initial Release.
36
+ - Initial Release.
37
+
data/evva.gemspec CHANGED
@@ -18,7 +18,4 @@ Gem::Specification.new do |s|
18
18
 
19
19
  s.add_runtime_dependency 'safe_yaml', '~> 1.0'
20
20
  s.add_runtime_dependency 'colorize', '~> 0.7'
21
- s.add_runtime_dependency 'xml-simple', '~> 1.1'
22
-
23
- s.add_development_dependency 'webmock', '~> 1.20'
24
21
  end
data/evva_config.yml CHANGED
@@ -3,8 +3,12 @@ type: iOS
3
3
  data_source:
4
4
  type: google_sheet
5
5
  sheet_id: 1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4
6
+ events_url: https://path-to-csv
7
+ people_properties_url: https://path-to-csv
8
+ enum_classes_url: https://path-to-csv
6
9
 
7
10
  out_path: analytics
8
11
  event_file_name: MixpanelAnalytics
9
12
  event_enum_file_name: MixpanelEvent
10
- people_file_name: MixpanelProperties
13
+ people_file_name: MixpanelProperties
14
+ package_name: com.hole19golf.hole19.analytics
@@ -1,48 +1,78 @@
1
1
  module Evva
2
2
  class AndroidGenerator
3
- KOTLIN_EVENT_HEADER =
4
- "package com.hole19golf.hole19.analytics\n\n"\
5
- "import com.hole19golf.hole19.analytics.Event\n"\
6
- "import com.hole19golf.hole19.analytics.MixpanelAnalyticsMask\n"\
7
- "import org.json.JSONObject\n\n".freeze
8
-
9
- KOTLIN_PEOPLE_HEADER =
10
- "package com.hole19golf.hole19.analytics\n"\
11
- "import com.hole19golf.hole19.analytics.Event\n\n".freeze
12
-
13
- KOTLIN_BUNDLE_HEADER =
14
- "package com.hole19golf.hole19.analytics\n"\
15
- "import com.hole19golf.hole19.analytics.Event\n\n".freeze
16
-
17
- KOTIN_PEOPLE_FUNCTIONS =
18
- "\nopen fun updateProperties(property: MixpanelProperties, value: Any) {\n"\
19
- "\t\tmixpanelMask.updateProperties(property.key, value)"\
20
- "\t\n} \n"\
21
- "\nopen fun incrementCounter(property: MixpanelProperties) {\n"\
22
- "\t\tmixpanelMask.incrementCounter(property.key)"\
23
- "\t\n} \n".freeze
3
+ attr_accessor :package_name
4
+
5
+ def initialize(package_name)
6
+ @package_name = package_name
7
+ end
8
+
9
+ IMPORT_EVENT = "import packagename.Event".freeze
10
+ IMPORT_MASK = "import packagename.MixpanelAnalyticsMask".freeze
11
+ IMPORT_JSON = "import org.json.JSONObject".freeze
24
12
 
25
13
  NATIVE_TYPES = %w[Long Int String Double Float Boolean].freeze
26
14
 
27
15
  def events(bundle, file_name)
28
- event_file = KOTLIN_EVENT_HEADER + "open class #{file_name}(private val mixpanelMask: MixpanelAnalyticsMask) {\n".freeze
29
- bundle.each do |event|
30
- event_file += "\n#{kotlin_function(event)}"
16
+ header_footer_wrapper([IMPORT_EVENT, IMPORT_MASK, IMPORT_JSON]) do
17
+ """open class #{file_name}(private val mask: MixpanelAnalyticsMask) {
18
+
19
+ #{bundle.map { |e| kotlin_function(e) }.join("\n\n")}
20
+
21
+ \topen fun updateProperties(property: MixpanelProperties, value: Any) {
22
+ \t\tmask.updateProperties(property.key, value)
23
+ \t}
24
+
25
+ \topen fun incrementCounter(property: MixpanelProperties) {
26
+ \t\tmask.incrementCounter(property.key)
27
+ \t}
28
+ }"""
31
29
  end
32
- event_file += KOTIN_PEOPLE_FUNCTIONS
33
- event_file += "\n}"
34
30
  end
35
31
 
36
32
  def people_properties(people_bundle, file_name)
37
- properties = KOTLIN_PEOPLE_HEADER + "enum class #{file_name}(val key: String) {\n"
38
- properties += people_bundle.map { |prop| "\t\t#{prop.upcase}(\"#{prop}\")" }.join(",\n")
39
- properties += ";\n}\n"
33
+ header_footer_wrapper do
34
+ body = "enum class MixpanelProperties(val key: String) {\n"
35
+ body << people_bundle.map { |prop| "\t#{prop.upcase}(\"#{prop}\")" }.join(",\n")
36
+ body << ";\n}"
37
+ end
40
38
  end
41
39
 
42
40
  def event_enum(bundle, file_name)
43
- event_file = KOTLIN_BUNDLE_HEADER + "enum class #{file_name}(override val key: String) : Event {\n"
44
- event_file += bundle.map { |event| "\t\t#{event.event_name.upcase}(\"#{event.event_name}\")"}.join(", \n")
45
- event_file += "\n}\n"
41
+ header_footer_wrapper([IMPORT_EVENT]) do
42
+ body = "enum class #{file_name}(override val key: String) : Event {\n"
43
+ body << bundle.map(&:event_name).map { |prop| "\t#{prop.upcase}(\"#{prop}\")" }.join(",\n")
44
+ body << ";\n}"
45
+ end
46
+ end
47
+
48
+ def special_property_enums(enums)
49
+ header_footer_wrapper do
50
+ enums.map do |enum|
51
+ body = "enum class #{enum.enum_name}(val key: String) {\n"
52
+ body << enum.values.map { |vals| "\t#{vals.tr(' ', '_').upcase}(\"#{vals}\")"}.join(",\n")
53
+ body << ";\n}"
54
+ end.join("\n\n")
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def imports_header(imports = [])
61
+ return unless imports.length > 0
62
+ imports.map { |ev| ev. gsub("packagename", @package_name) }
63
+ .join("\n") + "\n\n"
64
+ end
65
+
66
+ def header_footer_wrapper(imports = [])
67
+ <<-Kotlin
68
+ package #{@package_name}
69
+
70
+ #{imports_header(imports)}/**
71
+ * This file was automatically generated by evva: https://github.com/hole19/evva
72
+ */
73
+
74
+ #{yield.gsub("\t", " ")}
75
+ Kotlin
46
76
  end
47
77
 
48
78
  def kotlin_function(event_data)
@@ -50,27 +80,18 @@ module Evva
50
80
  function_arguments = event_data.properties.map { |name, type| "#{name}: #{type}" }.join(', ')
51
81
  if !function_arguments.empty?
52
82
  props = json_props(event_data.properties)
53
- function_body =
54
- "open fun #{function_name}(#{function_arguments}) {"\
55
- "#{props}"\
56
- "\tmixpanelMask.trackEvent(MixpanelEvent.#{event_data.event_name.upcase}, properties)\n"
83
+ """\topen fun #{function_name}(#{function_arguments}) {
84
+ #{props}
85
+ \t\tmask.trackEvent(MixpanelEvent.#{event_data.event_name.upcase}, properties)
86
+ \t}"""
87
+
57
88
  else
58
- function_body =
59
- "open fun #{function_name}() {\n"\
60
- "\tmixpanelMask.trackEvent(MixpanelEvent.#{event_data.event_name.upcase})\n"
89
+ """\topen fun #{function_name}() {
90
+ \t\tmask.trackEvent(MixpanelEvent.#{event_data.event_name.upcase})
91
+ \t}"""
61
92
  end
62
- function_body += "}\n"
63
- end
64
-
65
- def special_property_enum(enum)
66
- enum_body = "package com.hole19golf.hole19.analytics\n\n"
67
- enum_body += "enum class #{enum.enum_name}(val key: String) {\n"
68
- enum_body += enum.values.map { |vals| "\t#{vals.tr(' ', '_').upcase}(\"#{vals}\")"}.join(",\n")
69
- enum_body += "\n}\n"
70
93
  end
71
94
 
72
- private
73
-
74
95
  def json_props(properties)
75
96
  split_properties =
76
97
  properties
@@ -89,12 +110,10 @@ module Evva
89
110
  end
90
111
  end
91
112
  end
92
- .map { |line| "\t\t#{line}" }
113
+ .map { |line| "\t\t\t#{line}" }
93
114
  .join("\n")
94
115
 
95
- resulting_json = "\n\tval properties = JSONObject().apply {\n" +
96
- +split_properties.to_s
97
- resulting_json += "\n\t}\n"
116
+ "\t\tval properties = JSONObject().apply {\n#{split_properties}\n\t\t}"
98
117
  end
99
118
 
100
119
  def special_property?(type)
data/lib/evva/config.rb CHANGED
@@ -39,6 +39,14 @@ module Evva
39
39
  @hash[:event_enum_file_name]
40
40
  end
41
41
 
42
+ def special_enum_file_name
43
+ @hash[:special_enum_file_name]
44
+ end
45
+
46
+ def package_name
47
+ @hash[:package_name]
48
+ end
49
+
42
50
  CONFIG_STRUCT = {
43
51
  type: Hash,
44
52
  elements: {
@@ -49,7 +57,8 @@ module Evva
49
57
  out_path: { type: String },
50
58
  event_file_name: { type: String },
51
59
  event_enum_file_name: { type: String },
52
- people_file_name: { type: String }
60
+ people_file_name: { type: String },
61
+ package_name: { type: String }
53
62
  }
54
63
  }.freeze
55
64
 
@@ -57,7 +66,9 @@ module Evva
57
66
  type: Hash,
58
67
  elements: {
59
68
  type: { type: String },
60
- sheet_id: { type: String }
69
+ events_url: { type: String },
70
+ people_properties_url: { type: String },
71
+ enum_classes_url: { type: String },
61
72
  }
62
73
  }.freeze
63
74
 
@@ -1,83 +1,86 @@
1
1
  require 'net/https'
2
- require 'xmlsimple'
2
+ require 'csv'
3
3
 
4
4
  module Evva
5
5
  class GoogleSheet
6
- def initialize(sheet_id)
7
- @sheet_id = sheet_id
6
+ def initialize(events_url, people_properties_url, enum_classes_url)
7
+ @events_url = events_url
8
+ @people_properties_url = people_properties_url
9
+ @enum_classes_url = enum_classes_url
8
10
  end
9
11
 
10
12
  def events
11
- raw = raw_data(@sheet_id, 0)
12
- Logger.info('Downloading dictionary from Google Sheet...')
13
- non_language_columns = %w[id updated category
14
- title content link]
13
+ Logger.info("Downloading data from Google Sheet at #{@events_url}")
14
+ csv = get_csv(@events_url)
15
+
15
16
  event_list = []
16
- raw['entry'].each do |entry|
17
- filtered_entry = entry.reject { |c| non_language_columns.include?(c) }
18
- event_name = filtered_entry['eventname'].first
19
- properties = hash_parser(filtered_entry['props'].first)
20
- event_list.push(Evva::MixpanelEvent.new(event_name, properties))
17
+ csv.each do |row|
18
+ event_name = row['Event Name']
19
+ properties = hash_parser(row['Event Properties'])
20
+ event_list << Evva::MixpanelEvent.new(event_name, properties)
21
21
  end
22
22
  event_list
23
23
  end
24
24
 
25
25
  def people_properties
26
- raw = raw_data(@sheet_id, 1)
26
+ Logger.info("Downloading data from Google Sheet at #{@people_properties_url}")
27
+ csv = get_csv(@people_properties_url)
28
+
27
29
  people_list = []
28
- Logger.info('Downloading dictionary from Google Sheet...')
29
- non_language_columns = %w[id updated category title content link]
30
- raw['entry'].each do |entry|
31
- filtered_entry = entry.reject { |c| non_language_columns.include?(c) }
32
- value = filtered_entry['value'].first
30
+ csv.each do |row|
31
+ value = row['Property Name']
33
32
  people_list << value
34
33
  end
35
34
  people_list
36
35
  end
37
36
 
38
37
  def enum_classes
39
- raw = raw_data(@sheet_id, 2)
40
- Logger.info('Downloading dictionary from Google Sheet...')
41
- non_language_columns = %w[id updated category title content link]
38
+ Logger.info("Downloading data from Google Sheet at #{@enum_classes_url}")
39
+ csv = get_csv(@enum_classes_url)
40
+
42
41
  enum_list = []
43
- raw['entry'].each do |entry|
44
- filtered_entry = entry.reject { |c| non_language_columns.include?(c) }
45
- enum_name = filtered_entry['enum'].first
46
- values = filtered_entry['values'].first.split(',')
47
- enum_list.push(Evva::MixpanelEnum.new(enum_name, values))
42
+ csv.each do |row|
43
+ enum_name = row['Enum Name']
44
+ values = row['Possible Values'].split(',')
45
+ enum_list << Evva::MixpanelEnum.new(enum_name, values)
48
46
  end
49
47
  enum_list
50
48
  end
51
49
 
52
- def xml_data(uri, headers = nil)
53
- uri = URI.parse(uri)
54
- http = Net::HTTP.new(uri.host, uri.port)
55
- http.use_ssl = true
56
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
57
- data = http.get(uri.path, headers)
58
- unless data.code.to_i == 200
59
- raise 'Cannot access sheet at #{uri} - HTTP #{data.code}'
60
- end
50
+ private
51
+
52
+ def get_csv(url)
53
+ data = get(url)
61
54
 
62
55
  begin
63
- XmlSimple.xml_in(data.body, 'KeyAttr' => 'name')
64
- rescue
65
- raise 'Cannot parse. Expected XML at #{uri}'
56
+ CSV.parse(data, headers: true)
57
+ rescue StandardError => e
58
+ raise "Cannot parse. Expected CSV at #{url}: #{e}"
66
59
  end
67
60
  end
68
61
 
69
- def raw_data(sheet_id, sheet_number)
70
- Logger.info('Downloading Google Sheet...')
71
- sheet = xml_data("https://spreadsheets.google.com/feeds/worksheets/#{sheet_id}/public/full")
72
- url = sheet['entry'][sheet_number]['link'][0]['href']
73
- xml_data(url)
74
- end
62
+ def get(url, max_redirects = 1)
63
+ raise "Too may redirects" if max_redirects == -1
75
64
 
76
- private
65
+ uri = URI(url)
66
+
67
+ http = Net::HTTP.new(uri.host, uri.port)
68
+ http.use_ssl = true
69
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
70
+
71
+ request = Net::HTTP::Get.new(uri.request_uri)
72
+ response = http.request(request)
73
+
74
+ return get(response['location'], max_redirects - 1) if response.is_a? Net::HTTPRedirection
75
+
76
+ raise "Http Error #{response.body}" if response.code.to_i >= 400
77
+
78
+ response.body
79
+ end
77
80
 
78
81
  def hash_parser(property_array)
79
82
  h = {}
80
- unless property_array.empty?
83
+ unless property_array.nil? || property_array.empty?
81
84
  property_array.split(',').each do |prop|
82
85
  split_prop = prop.split(':')
83
86
  prop_name = split_prop[0].to_sym