terrestrial-cli 0.1.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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +134 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +7 -0
  12. data/bin/terrestrial +44 -0
  13. data/circle.yml +11 -0
  14. data/lib/terrestrial/cli/android_xml_formatter.rb +43 -0
  15. data/lib/terrestrial/cli/android_xml_parser.rb +49 -0
  16. data/lib/terrestrial/cli/bootstrapper.rb +184 -0
  17. data/lib/terrestrial/cli/command.rb +20 -0
  18. data/lib/terrestrial/cli/detects_project_type.rb +16 -0
  19. data/lib/terrestrial/cli/dot_strings_formatter.rb +53 -0
  20. data/lib/terrestrial/cli/dot_strings_parser.rb +139 -0
  21. data/lib/terrestrial/cli/editor/android_xml.rb +64 -0
  22. data/lib/terrestrial/cli/editor/base_editor.rb +36 -0
  23. data/lib/terrestrial/cli/editor/objc.rb +66 -0
  24. data/lib/terrestrial/cli/editor/printer.rb +47 -0
  25. data/lib/terrestrial/cli/editor/storyboard.rb +98 -0
  26. data/lib/terrestrial/cli/editor/swift.rb +92 -0
  27. data/lib/terrestrial/cli/editor.rb +42 -0
  28. data/lib/terrestrial/cli/engine_mapper.rb +30 -0
  29. data/lib/terrestrial/cli/entry_collection_differ.rb +22 -0
  30. data/lib/terrestrial/cli/file_finder.rb +65 -0
  31. data/lib/terrestrial/cli/file_picker.rb +58 -0
  32. data/lib/terrestrial/cli/flight/ios_workflow.rb +81 -0
  33. data/lib/terrestrial/cli/flight/table_workflow.rb +77 -0
  34. data/lib/terrestrial/cli/flight.rb +93 -0
  35. data/lib/terrestrial/cli/ignite.rb +73 -0
  36. data/lib/terrestrial/cli/init.rb +133 -0
  37. data/lib/terrestrial/cli/mixpanel_client.rb +56 -0
  38. data/lib/terrestrial/cli/parser/android_xml.rb +82 -0
  39. data/lib/terrestrial/cli/parser/base_parser.rb +42 -0
  40. data/lib/terrestrial/cli/parser/objc.rb +127 -0
  41. data/lib/terrestrial/cli/parser/storyboard.rb +166 -0
  42. data/lib/terrestrial/cli/parser/string_analyser.rb +115 -0
  43. data/lib/terrestrial/cli/parser/swift.rb +102 -0
  44. data/lib/terrestrial/cli/parser.rb +25 -0
  45. data/lib/terrestrial/cli/photoshoot.rb +65 -0
  46. data/lib/terrestrial/cli/pull.rb +110 -0
  47. data/lib/terrestrial/cli/push.rb +40 -0
  48. data/lib/terrestrial/cli/scan.rb +72 -0
  49. data/lib/terrestrial/cli/string_registry.rb +30 -0
  50. data/lib/terrestrial/cli/terminal_ui.rb +25 -0
  51. data/lib/terrestrial/cli/variable_normalizer.rb +34 -0
  52. data/lib/terrestrial/cli/version.rb +5 -0
  53. data/lib/terrestrial/cli.rb +82 -0
  54. data/lib/terrestrial/config.rb +99 -0
  55. data/lib/terrestrial/creates_terrestrial_yml.rb +9 -0
  56. data/lib/terrestrial/web/response.rb +17 -0
  57. data/lib/terrestrial/web.rb +78 -0
  58. data/lib/terrestrial/yaml_helper.rb +48 -0
  59. data/lib/terrestrial.rb +7 -0
  60. data/terrestrial-cli.gemspec +29 -0
  61. metadata +188 -0
@@ -0,0 +1,65 @@
1
+ module Terrestrial
2
+ module Cli
3
+ class FileFinder
4
+
5
+ EXCLUDED_FOLDERS = [
6
+ /Carthage\//,
7
+ /Pods\//,
8
+ /Tests\//
9
+ ]
10
+
11
+ EXCLUDED_FILES = [
12
+ "LaunchScreen.storyboard"
13
+ ]
14
+
15
+ def self.find(directory, extensions)
16
+ self.new(directory, extensions).find
17
+ end
18
+
19
+ def initialize(directory, extensions)
20
+ @directory = directory
21
+ @extensions = extensions
22
+ end
23
+
24
+ def find
25
+ Dir[@directory + "/**/*.*"]
26
+ .map {|f| relative_path(f) }
27
+ .reject {|f| excluded_folders(f) }
28
+ .select {|f| @extensions.include?(File.extname(f)) }
29
+ .reject {|f| excluded_files(f) }
30
+ .select {|f| valid_paths(f) }
31
+ end
32
+
33
+ private
34
+
35
+ def relative_path(file)
36
+ Pathname.new(file)
37
+ .relative_path_from(Pathname.new(@directory))
38
+ .to_s
39
+ end
40
+
41
+ def valid_paths(f)
42
+ # Some files need to be in specific places to count
43
+ # as "real files". For example, strings.xml files should
44
+ # only be read if they are in /res/values/strings.xml
45
+ #
46
+ # Add rules here as needed.
47
+
48
+ case File.extname(f)
49
+ when ".xml"
50
+ f.end_with? "/res/values/strings.xml"
51
+ else
52
+ true
53
+ end
54
+ end
55
+
56
+ def excluded_folders(path)
57
+ EXCLUDED_FOLDERS.any? { |folder| path.scan(folder).any? }
58
+ end
59
+
60
+ def excluded_files(path)
61
+ EXCLUDED_FILES.any? { |name| File.basename(path) == name }
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,58 @@
1
+ require 'pathname'
2
+
3
+ module Terrestrial
4
+ module Cli
5
+ class FilePicker
6
+ class << self
7
+
8
+ def run(files, platform)
9
+ if files.count == 1
10
+ single_file_workflow(files)
11
+ else
12
+ multiple_files_workflow(files)
13
+ end
14
+ end
15
+
16
+ def multiple_files_workflow(files)
17
+ puts "-- Terrestrial detected #{files.count} localization files:"
18
+ files.each_with_index do |path, i|
19
+ puts "(#{i + 1}) #{path}"
20
+ end
21
+ puts ""
22
+ puts "Select the files you want Terrestrial to track as the base localization: e.g. \"1,4,5\""
23
+ puts "(To not select any files, just hit return. You can edit tracked files in terrestrial.yml)"
24
+
25
+ result = STDIN.gets.chomp
26
+
27
+ process_result(result, files)
28
+ end
29
+
30
+ def single_file_workflow(files)
31
+ puts "Terrestrial detected #{files.count} file:"
32
+ puts "(1) #{files[0].to_s}"
33
+ puts ""
34
+ puts "Use this file as your base language file? (you can change this late in terrestrial.yml) y/n?"
35
+
36
+ result = STDIN.gets.chomp.strip
37
+
38
+ if result == "y"
39
+ files
40
+ else
41
+ []
42
+ end
43
+ end
44
+
45
+ def process_result(result, files)
46
+ if result == ""
47
+ return []
48
+ else
49
+ result
50
+ .split(",")
51
+ .map {|i| i.to_i}
52
+ .map {|i| files[i - 1]}
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,81 @@
1
+ module Terrestrial
2
+ module Cli
3
+ class Flight < Command
4
+ class IosWorkflow
5
+
6
+ def initialize(bootstrap_results)
7
+ @results = bootstrap_results
8
+ end
9
+
10
+ def run
11
+ print_instructions
12
+ command = STDIN.gets.chomp
13
+
14
+ if command == "y"
15
+ lproj_folder = TerminalUI.show_spinner do
16
+ Editor.prepare_files(results.all_occurences)
17
+ initalize_localizable_strings_files
18
+ end
19
+ add_file_to_config(lproj_folder)
20
+ print_done_message(lproj_folder)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def initalize_localizable_strings_files
27
+ path = create_path_to_localization_files
28
+
29
+ File.open(path, "a+") do |f|
30
+ formatter = DotStringsFormatter.new(results)
31
+
32
+ f.write "// Created by Terrestrial (#{Time.now.to_s})"
33
+ f.write "\n\n"
34
+ f.write formatter.format
35
+ end
36
+ path
37
+ end
38
+
39
+ def create_path_to_localization_files
40
+ folder_name = Pathname.new(Dir[Config[:directory] + "/*.xcodeproj"].first).basename(".*").to_s
41
+ base_lproj_path = FileUtils.mkdir_p(Config[:directory] + "/#{folder_name}" + "/Base.lproj").first
42
+
43
+ base_lproj_path + "/Localizable.strings"
44
+ end
45
+
46
+ def add_file_to_config(path)
47
+ path_to_file = Pathname.new(path)
48
+ current_dir = Pathname.new(Config[:directory])
49
+
50
+ Config.load({ translation_files: [
51
+ path_to_file.relative_path_from(current_dir).to_s
52
+ ]})
53
+ Config.update_project_config
54
+ end
55
+
56
+ def print_done_message(lproj_folder)
57
+ puts "------------------------------------"
58
+ puts "-- Done!"
59
+ puts "- Created Base.lproj in #{lproj_folder}."
60
+ puts "- Remember to include the new localization files in your project!"
61
+ end
62
+
63
+ def print_instructions
64
+ puts "- Terrestrial will add #{results.length} strings to your base Localizable.strings."
65
+ puts ""
66
+ puts "------------------------------------"
67
+ puts "-- Source Code"
68
+ puts "- Would you like Terrestrial to also modify the selected strings in your"
69
+ puts "- source code to call .translated?"
70
+ puts "- e.g. \"This is my string\" => \"This is my string\".translated"
71
+ puts ""
72
+ puts "y/n?"
73
+ end
74
+
75
+ def results
76
+ @results
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,77 @@
1
+ module Terrestrial
2
+ module Cli
3
+ class Flight < Command
4
+ class TableWorkflow
5
+
6
+ LOCAL_CONFIG = {
7
+ strings_per_page: 10
8
+ }
9
+
10
+ def initialize(bootstrap_results)
11
+ @results = bootstrap_results
12
+ end
13
+
14
+ def run
15
+ print_instructions
16
+
17
+ exclusions = []
18
+ i = 0
19
+
20
+ results.all_occurences.each_slice(LOCAL_CONFIG[:strings_per_page]).with_index do |five_strings, index|
21
+ puts "Page #{index + 1} of #{(results.all_occurences.count / LOCAL_CONFIG[:strings_per_page].to_f).ceil}"
22
+
23
+ table = create_string_table(five_strings, i)
24
+ i += LOCAL_CONFIG[:strings_per_page]
25
+ puts table
26
+ print_instructions
27
+ puts ""
28
+
29
+ command = STDIN.gets.chomp
30
+ if command == 'q'
31
+ abort "Aborting..."
32
+ else
33
+ begin
34
+ exclusions.concat(command.split(",").map(&:to_i))
35
+ rescue
36
+ abort "Couldn't process that command :( Aborting..."
37
+ end
38
+ end
39
+ end
40
+ exclusions
41
+ end
42
+
43
+ private
44
+
45
+ def create_string_table(strings, i)
46
+ Terminal::Table.new(headings: ['Index', 'String', 'File']) do |t|
47
+ strings.each_with_index do |string, tmp_index|
48
+ t.add_row([i, string.string, file_name_with_line_number(string)])
49
+ t.add_separator unless tmp_index == (strings.length - 1) || i == (strings.length - 1)
50
+ i += 1
51
+ end
52
+ end
53
+ end
54
+
55
+ def print_instructions
56
+ puts "-- Instructions --"
57
+ puts "- To exclude any strings from translation, type the index of each string."
58
+ puts "- e.g. 1,2,4"
59
+ puts "------------------"
60
+ puts "Any Exclusions? (press return to continue or 'q' to quit at any time)"
61
+ end
62
+
63
+ def file_name_with_line_number(string)
64
+ if string.line_number
65
+ "#{string.file}:#{string.line_number}"
66
+ else
67
+ string.file
68
+ end
69
+ end
70
+
71
+ def results
72
+ @results
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,93 @@
1
+ require 'terrestrial/cli/flight/ios_workflow.rb'
2
+ require 'terrestrial/cli/flight/table_workflow.rb'
3
+ require 'terminal-table'
4
+ require 'pathname'
5
+
6
+ module Terrestrial
7
+ module Cli
8
+ class Flight < Command
9
+
10
+ def run
11
+ Config.load!
12
+ MixpanelClient.track("cli-flight-command")
13
+
14
+ if !Config.project_config_exist?
15
+ abort_not_initialized
16
+ end
17
+ if Config[:translation_files].any?
18
+ abort_already_run_flight
19
+ end
20
+ if Config[:platform] != "ios"
21
+ puts "'flight' is not supported on Android."
22
+ puts " iOS projects often just include strings in their source code instead of extracting them into resource files."
23
+ puts " We created 'flight' to get iOS project up and running quicker."
24
+ puts " 'R.string' makes localization much easier :)"
25
+ abort
26
+ end
27
+
28
+ puts "- Finding untranslated human readable strings..."
29
+ TerminalUI.show_spinner do
30
+ find_new_strings
31
+ end
32
+
33
+ puts "------------------------------------"
34
+ puts "- Found #{strings.count} strings"
35
+ puts ""
36
+ exclusions = TableWorkflow.new(strings).run
37
+ puts "------------------------------------"
38
+ puts "- Done!"
39
+
40
+ strings.exclude_occurences(exclusions)
41
+
42
+ if Config[:platform] == "ios"
43
+ IosWorkflow.new(strings).run
44
+ elsif Config[:platform] == 'android'
45
+ android_workflow
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def android_workflow
52
+ puts "- Terrestrial will annotate the selected strings in your strings.xml file:"
53
+ puts "- e.g. <string name='my_name'>My string!</string> => <string terrestrial='true' name='my_name'>My string</string>"
54
+ end
55
+
56
+ def find_new_strings
57
+ @strings = Bootstrapper.find_new_strings(Config[:directory])
58
+ end
59
+
60
+ def strings
61
+ @strings
62
+ end
63
+
64
+ def abort_not_initialized
65
+ puts "You should initialize your project before running flight."
66
+ puts "It's simple! You can do this by running:"
67
+ puts ""
68
+ puts " terrestrial init --api-key <API KEY> --project-id <PROJECT ID>"
69
+ puts ""
70
+ puts "You can find your Api Key and Project ID at https://mission.terrestrial.io"
71
+ abort
72
+ end
73
+
74
+ def abort_already_run_flight
75
+ if Config[:platform] == "ios"
76
+ puts "Looks like you already have Localizable.strings files."
77
+ puts "'flight' scans your source code for human readable strings that have not been translated"
78
+ puts "and helps you quickstart your internaionalization process."
79
+ puts ""
80
+ puts "If you want to new strings into your .strings file, run 'terrestrial gen'. It will:"
81
+ puts " 1. Scan your source code for .translated and NSLocalizedString calls."
82
+ puts " 2. Determine if the strings already exist in Localizable.strings."
83
+ puts " 3. Append any new strings to your base Localizable.strings."
84
+ puts ""
85
+ puts "For more information, visit http://docs.terrestrial.io/, or jump on our Slack via https://terrestrial-slack.herokuapp.com/"
86
+ abort
87
+ else
88
+ # TODO
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,73 @@
1
+ module Terrestrial
2
+ module Cli
3
+ class Ignite < Command
4
+
5
+ WORKING_DIR = '/usr/local/var/terrestrial'
6
+
7
+ def run
8
+ Config.load!
9
+ MixpanelClient.track("cli-ignite-command")
10
+ lang = opts["language"]
11
+
12
+ if Config[:platform] != "ios"
13
+ abort "Unfortunately launching your app in a locale via 'ignite' is only supported on iOS at this time."
14
+ end
15
+
16
+ if lang.nil? || lang.empty?
17
+ abort "Please provide a locale to launch the simulator in.\n e.g. 'terrestrial ignite es'"
18
+ end
19
+
20
+ puts "Starting simulator in locale \"#{lang}\"..."
21
+
22
+ TerminalUI.show_spinner do
23
+ ensure_var_folder_exists
24
+
25
+ workspace = Dir["#{Config[:directory]}/*.xcworkspace"][0]
26
+ project = Dir["#{Config[:directory]}/*.xcodeproj"][0]
27
+
28
+ # Kill simulator and
29
+ system("killall \"Simulator\" &> /dev/null")
30
+ `rm -rf #{WORKING_DIR}`
31
+
32
+ if workspace
33
+ # If a workspace exists we want to build it instead of the project.
34
+ # We assume the scheme we want to use is simply the application name
35
+ app_name = File.basename(workspace).split(".").first
36
+ `xcodebuild -workspace "#{workspace}" -arch "i386" ONLY_ACTIVE_ARCH=NO VALID_ARCHS="i386 x86_64" -scheme #{app_name} -sdk iphonesimulator clean`
37
+ `xcodebuild -workspace "#{workspace}" -arch "i386" ONLY_ACTIVE_ARCH=NO VALID_ARCHS="i386 x86_64" -scheme #{app_name} -sdk iphonesimulator CONFIGURATION_BUILD_DIR=#{WORKING_DIR}`
38
+ else
39
+ app_name = File.basename(project).split(".").first
40
+ `xcodebuild -project "#{project}" -arch i386 -sdk iphonesimulator clean`
41
+ `xcodebuild -project "#{project}" -arch i386 -sdk iphonesimulator CONFIGURATION_BUILD_DIR=#{WORKING_DIR}`
42
+ end
43
+ `open /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app`
44
+
45
+ # Here we literally sleep until the Simulator has been booted
46
+ wait_until_booted = %{
47
+ count=`xcrun simctl list | grep Booted | wc -l | sed -e 's/ //g'`
48
+ while [ $count -lt 1 ]
49
+ do
50
+ sleep 1
51
+ count=`xcrun simctl list | grep Booted | wc -l | sed -e 's/ //g'`
52
+ done
53
+ }
54
+ `#{wait_until_booted}`
55
+
56
+ # Here we magically find the bundle identifier of the app
57
+ command = "defaults read \"#{Dir[WORKING_DIR + '/*.app/Info.plist'].first}\" CFBundleIdentifier"
58
+ bundle_name = `#{command}`.chop
59
+
60
+ # Reinstall the app,
61
+ # Run it with the locale we want
62
+ `xcrun simctl uninstall booted #{bundle_name}`
63
+ `xcrun simctl install booted "#{Dir[WORKING_DIR + "/" + app_name + ".app"].first}"`
64
+ `xcrun simctl launch booted #{bundle_name} --args -AppleLanguages \\(#{lang}\\)`
65
+ end
66
+ end
67
+
68
+ def ensure_var_folder_exists
69
+ `mkdir -p #{WORKING_DIR}`
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,133 @@
1
+ module Terrestrial
2
+ module Cli
3
+ class Init < Command
4
+
5
+ def run
6
+ # Fail early if project already exists
7
+ Config.load!({}, project: false)
8
+ MixpanelClient.track("cli-init-command")
9
+
10
+ if Config.project_config_exist?
11
+ abort "Looks like there already exists a project in this directory. Are you in the correct folder?"
12
+ end
13
+
14
+ check_arguments
15
+ detect_platform
16
+
17
+ puts "-- Terrestrial Initializing"
18
+ puts "Adding new app! Searching for localization files..."
19
+
20
+ TerminalUI.show_spinner do
21
+ # Otherwise the whole process is too quick for the eye
22
+ sleep 2 unless Config.testing?
23
+ end
24
+ puts ""
25
+
26
+ select_translation_files
27
+ create_app_in_web
28
+
29
+ if @response.success?
30
+ update_config
31
+
32
+ puts "-- Success!"
33
+ puts "App platform added to project! You can view your app at https://mission.terrestrial.io/projects/#{Config[:project_id]}/apps/#{Config[:app_id]}"
34
+ puts ""
35
+ puts "-- What to do next?"
36
+
37
+ if @translation_files.any?
38
+ puts "Run 'terrestrial scan' to see which strings Terrestrial is currently tracking."
39
+ puts "When you're ready to upload your strings for translation, run 'terrestrial push'!"
40
+ elsif @translation_files.none? && @platform == "ios"
41
+ puts "To get started localizing your app, run 'terrestrial flight'."
42
+ puts "Terrestrial will scan your code for strings, and generate the necessary localization files."
43
+ elsif @translation_files.none? && @platform == "android"
44
+ puts "Looks like Terrestrial does not know which strings.xml files to track."
45
+ puts "To continue, add your base language strings.xml file to terrestrial.yml."
46
+ puts "When you're ready, run 'terrestrial scan' to see which strings Terrestrial is tracking, and 'terrestrial push' to upload."
47
+ end
48
+ puts ""
49
+ puts "For more information, see http://docs.terrestrial.io or jump on Slack at https://terrestrial-slack.herokuapp.com/ if you have any questions."
50
+ else
51
+ puts "Oh snap. There was an error initializing your project."
52
+ puts response.body.inspect
53
+ abort
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def select_translation_files
60
+ @tranlation_files = []
61
+
62
+ files = find_platform_translation_files
63
+ if files.any?
64
+ @tranlation_files = FilePicker.run(files, @platform)
65
+
66
+ if @tranlation_files.count == 1
67
+ puts "Tracking #{@tranlation_files.count} file!"
68
+ else
69
+ puts "Tracking #{@tranlation_files.count} files!"
70
+ end
71
+ end
72
+ end
73
+
74
+ def find_platform_translation_files
75
+ if @platform == "ios"
76
+ Dir[Config[:directory] + "/**/*.strings"].map {|f| relative_path(f) }
77
+ elsif @platform == "android"
78
+ Dir[Config[:directory] + "/**/*/res/values/strings.xml"].map {|f| relative_path(f) }
79
+ else
80
+ raise "Unknown platform #{@platform}"
81
+ end
82
+ end
83
+
84
+ def update_config
85
+ Terrestrial::Config.load({
86
+ app_id: @response.body["data"]["id"],
87
+ project_id: @project_id,
88
+ platform: @platform,
89
+ api_key: @api_key,
90
+ translation_files: @tranlation_files
91
+ })
92
+
93
+ Terrestrial::Config.update_global_config
94
+ Terrestrial::Config.update_project_config
95
+ end
96
+
97
+ def create_app_in_web
98
+ @client = Terrestrial::Web.new(@api_key)
99
+ @response = @client.create_app(@project_id, @platform)
100
+ end
101
+
102
+ def check_arguments
103
+ @api_key = opts[:api_key] || Config[:api_key] ||
104
+ abort("No api key provided. You can find your API key at https://mission.terrestrial.io/.")
105
+
106
+ @project_id = opts.fetch(:project_id) { abort(
107
+ "No project ID provided. Terrestrial needs to know which project this app belongs to.\n" +
108
+ "Visit https://mission.terrestrial.io to find your project ID."
109
+ )}
110
+ end
111
+
112
+ def detect_platform
113
+ @platform = DetectsProjectType.run
114
+ end
115
+
116
+ def project_id
117
+ @project_id
118
+ end
119
+
120
+ def api_key
121
+ @api_key
122
+ end
123
+
124
+ def relative_path(file)
125
+ current_dir = Pathname.new(Config[:directory])
126
+
127
+ Pathname.new(file)
128
+ .relative_path_from(current_dir)
129
+ .to_s
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,56 @@
1
+ require 'base64'
2
+ require 'json'
3
+
4
+ module Terrestrial
5
+ module Cli
6
+ module MixpanelClient
7
+ class << self
8
+
9
+ TOKEN = "47d6a27568a3c842ead24b14907eb04e"
10
+ URL = "https://api.mixpanel.com/track"
11
+
12
+ def track(event)
13
+ # If we're live
14
+ if Config[:api_url] == "https://mission.terrestrial.io"
15
+ `curl -silent -X POST #{URL}?data=#{format_event(event)} &`
16
+ end
17
+ end
18
+
19
+ def user_identifier
20
+ if Config[:user_id]
21
+ Config[:user_id]
22
+ else
23
+ fetch_and_save_user_id
24
+ end
25
+ end
26
+
27
+ def format_event(event)
28
+ Base64.strict_encode64(event_json(event))
29
+ end
30
+
31
+ def event_json(event)
32
+ {
33
+ event: event,
34
+ properties: {
35
+ distinct_id: user_identifier,
36
+ token: TOKEN,
37
+ time: Time.now.to_i
38
+ }
39
+ }.to_json
40
+ end
41
+
42
+ def fetch_and_save_user_id
43
+ response = Web.new.get_profile
44
+ if response.success?
45
+ id = response.body["data"]["user"]["id"]
46
+ Config.load({:user_id => id})
47
+ Config.update_global_config
48
+ id
49
+ else
50
+ "unknown"
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end