terrestrial-cli 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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 Photoshoot < Command
4
+
5
+ WORKING_DIR = '/usr/local/var/terrestrial'
6
+
7
+ def run
8
+ Config.load!
9
+ MixpanelClient.track("cli-photoshoot-command")
10
+
11
+ if Config[:platform] != "ios"
12
+ abort "Unfortunately photoshoot mode is only supported on iOS at this time."
13
+ end
14
+
15
+ puts "Starting simulator in photoshoot mode..."
16
+ ensure_var_folder_exists
17
+
18
+ workspace = Dir["#{Config[:directory]}/*.xcworkspace"][0]
19
+ project = Dir["#{Config[:directory]}/*.xcodeproj"][0]
20
+
21
+ # Kill simulator and
22
+ system("killall \"Simulator\" &> /dev/null")
23
+ `rm -rf #{WORKING_DIR}`
24
+
25
+ if workspace
26
+ # If a workspace exists we want to build it instead of the project.
27
+ # We assume the scheme we want to use is simply the application name
28
+ app_name = File.basename(workspace).split(".").first
29
+ `xcodebuild -workspace "#{workspace}" -arch "i386" ONLY_ACTIVE_ARCH=NO VALID_ARCHS="i386 x86_64" -scheme #{app_name} -sdk iphonesimulator clean`
30
+ `xcodebuild -workspace "#{workspace}" -arch "i386" ONLY_ACTIVE_ARCH=NO VALID_ARCHS="i386 x86_64" -scheme #{app_name} -sdk iphonesimulator CONFIGURATION_BUILD_DIR=#{WORKING_DIR}`
31
+ else
32
+ app_name = File.basename(project).split(".").first
33
+ `xcodebuild -project "#{project}" -arch i386 -sdk iphonesimulator clean`
34
+ `xcodebuild -project "#{project}" -arch i386 -sdk iphonesimulator CONFIGURATION_BUILD_DIR=#{WORKING_DIR}`
35
+ end
36
+ `open /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app`
37
+
38
+ # Here we literally sleep until the Simulator has been booted
39
+ wait_until_booted = %{
40
+ count=`xcrun simctl list | grep Booted | wc -l | sed -e 's/ //g'`
41
+ while [ $count -lt 1 ]
42
+ do
43
+ sleep 1
44
+ count=`xcrun simctl list | grep Booted | wc -l | sed -e 's/ //g'`
45
+ done
46
+ }
47
+ `#{wait_until_booted}`
48
+
49
+ # Here we magically find the bundle identifier of the app
50
+ command = "defaults read \"#{Dir[WORKING_DIR + '/*.app/Info.plist'].first}\" CFBundleIdentifier"
51
+ bundle_name = `#{command}`.chop
52
+
53
+ # Reinstall the app,
54
+ # Run it with the locale we want
55
+ `xcrun simctl uninstall booted #{bundle_name}`
56
+ `xcrun simctl install booted "#{Dir[WORKING_DIR + "/" + app_name + ".app"].first}"`
57
+ `xcrun simctl launch booted #{bundle_name} --args -TerrestrialScreenShotMode YES -TerrestrialAPIToken "#{Config[:api_key]}" -TerrestrialAppId "#{Config[:app_id]}" -TerrestrialProjectId "#{Config[:project_id]}" -TerrestrialURL "#{Config[:api_url]}"`
58
+ end
59
+
60
+ def ensure_var_folder_exists
61
+ `mkdir -p #{WORKING_DIR}`
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,110 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+
4
+ module Terrestrial
5
+ module Cli
6
+ class Pull < Command
7
+
8
+ def run
9
+ Config.load!
10
+ MixpanelClient.track("cli-pull-command")
11
+
12
+ fetch_translations
13
+ languages.each do |lang, translations|
14
+ update_translation_file(lang, translations)
15
+ end
16
+ print_confirmation
17
+ end
18
+
19
+ private
20
+
21
+ def print_confirmation
22
+ if languages.size == 1
23
+ puts "Fetched latest translations for '#{languages.keys.first}'"
24
+ elsif languages.size == 0
25
+ puts "No translations to fetch..."
26
+ else
27
+ puts "Fetched latest translations for #{languages.size} languages: #{languages.keys.map {|l| "'#{l}'"}.join(", ")}."
28
+ end
29
+ end
30
+
31
+ def update_translation_file(language, translations)
32
+ write_translation_file(
33
+ translation_file_path_for(language),
34
+ translations
35
+ .reject {|entry| entry["translation"].nil? || entry["translation"].empty? }
36
+ .map {|entry| TranslatedString.new(entry["translation"], entry["id"]) }
37
+ )
38
+ end
39
+
40
+ def translation_file_path_for(language)
41
+ if Config[:platform] == "ios"
42
+ ios_translation_file_path(language)
43
+ elsif Config[:platform] == "android"
44
+ android_translation_file_path(language)
45
+ end
46
+ end
47
+
48
+ def ios_translation_file_path(language)
49
+ folder = Pathname.new(Config[:directory] + "/" + Config[:translation_files].first)
50
+ .parent
51
+ .parent
52
+ .to_s + "/#{format_language_code(language)}.lproj"
53
+
54
+ FileUtils.mkdir_p(folder)
55
+ folder + "/Localizable.strings"
56
+ end
57
+
58
+ def android_translation_file_path(language)
59
+ folder = Pathname.new(Config[:directory] + "/" + Config[:translation_files].first)
60
+ .parent
61
+ .parent
62
+ .to_s + "/values-#{format_language_code(language)}"
63
+
64
+ FileUtils.mkdir_p(folder)
65
+ folder + "/strings.xml"
66
+ end
67
+
68
+ def write_translation_file(path, translations)
69
+ File.open(path, "w+") do |f|
70
+ if Config[:platform] == "ios"
71
+ f.write "// Updated by Terrestrial #{Time.now.to_s}\n\n"
72
+ f.write DotStringsFormatter.new(translations).format_foreign_translation
73
+ elsif Config[:platform] == "android"
74
+ f.write "<!-- Updated by Terrestrial #{Time.now.to_s} -->\n\n"
75
+ f.write AndroidXmlFormatter.new(translations).format_foreign_translation
76
+ end
77
+ end
78
+ end
79
+
80
+ def format_language_code(language)
81
+ lang, region = language.split("-")
82
+
83
+ if region
84
+ "#{lang}_#{region.upcase}"
85
+ else
86
+ lang
87
+ end
88
+ end
89
+
90
+ def fetch_translations
91
+ @response = web_client.get_translations(Config[:project_id], Config[:app_id])
92
+ end
93
+
94
+ def languages
95
+ response.body["data"]["translations"]
96
+ end
97
+
98
+ def response
99
+ @response
100
+ end
101
+
102
+ def web_client
103
+ @web_client ||= Web.new
104
+ end
105
+
106
+ class TranslatedString < Struct.new(:string, :identifier)
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,40 @@
1
+ module Terrestrial
2
+ module Cli
3
+ class Push < Command
4
+
5
+ def run
6
+ Config.load!
7
+ MixpanelClient.track("cli-push-command")
8
+ load_string_registry
9
+
10
+ web_client.push(Config[:project_id], Config[:app_id], format_entries)
11
+
12
+ puts "Success!"
13
+ end
14
+
15
+ private
16
+
17
+ def format_entries
18
+ string_registry.entries.map do |entry|
19
+ {
20
+ "string" => entry["string"],
21
+ "context" => entry["context"],
22
+ "identifier" => entry["identifier"]
23
+ }
24
+ end
25
+ end
26
+
27
+ def load_string_registry
28
+ @string_registry = StringRegistry.load
29
+ end
30
+
31
+ def web_client
32
+ @web_client ||= Web.new
33
+ end
34
+
35
+ def string_registry
36
+ @string_registry
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,72 @@
1
+ require 'terminal-table'
2
+
3
+ module Terrestrial
4
+ module Cli
5
+ class Scan < Command
6
+
7
+ def run
8
+ Config.load!
9
+ MixpanelClient.track("cli-scan-command")
10
+
11
+ TerminalUI.show_spinner do
12
+ @string_registry = StringRegistry.load
13
+ @remote_registry = fetch_current_strings_from_web
14
+ end
15
+
16
+ print_results
17
+ end
18
+
19
+ private
20
+
21
+ def print_results
22
+ puts "New Strings: #{new_strings.count}"
23
+ puts "Removed Strings: #{removed_strings.count}"
24
+
25
+ if opts[:verbose]
26
+ print_diff
27
+ else
28
+ if rand(10) == 1 # Show hint ~10% of the time
29
+ puts "(Hint: add --verbose to the 'scan' command to view the diff of local and remote strings.)"
30
+ end
31
+ end
32
+ end
33
+
34
+ def print_diff
35
+ puts "--- Diff"
36
+ puts "- New Strings"
37
+ print_table(new_strings)
38
+ puts ""
39
+ puts "- Removed Strings"
40
+ print_table(removed_strings)
41
+ end
42
+
43
+ def print_table(strings)
44
+ puts Terminal::Table.new(headings: ['Identifier', 'String', 'Comment']) do |t|
45
+ size = strings.count
46
+ strings.each_with_index do |string, i|
47
+ t.add_row([string["identifier"], string["string"], string["context"]])
48
+ t.add_separator unless i == (size - 1)
49
+ end
50
+ end
51
+ end
52
+
53
+ def new_strings
54
+ EntryCollectionDiffer.additions(@remote_registry, @string_registry.entries)
55
+ end
56
+
57
+ def removed_strings
58
+ EntryCollectionDiffer.omissions(@remote_registry, @string_registry.entries)
59
+ end
60
+
61
+ def fetch_current_strings_from_web
62
+ web_client
63
+ .get_app_strings(Config[:project_id], Config[:app_id])
64
+ .body["data"]["strings"]
65
+ end
66
+
67
+ def web_client
68
+ @web_client ||= Web.new
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,30 @@
1
+ module Terrestrial
2
+ module Cli
3
+ class StringRegistry
4
+
5
+ def self.load
6
+ entries = Config[:translation_files].flat_map do |file|
7
+ begin
8
+ if Config[:platform] == "ios"
9
+ DotStringsParser.parse_file(Config[:directory] + "/#{file}")
10
+ elsif Config[:platform] == "android"
11
+ AndroidXmlParser.parse_file(Config[:directory] + "/#{file}")
12
+ end
13
+ rescue Errno::ENOENT
14
+ abort "Could not find #{file}. If the file is no longer in your project, remove it from your tracked files in terrestrial.yml."
15
+ end
16
+ end
17
+
18
+ new(entries)
19
+ end
20
+
21
+ def initialize(entries)
22
+ @entries = entries
23
+ end
24
+
25
+ def entries
26
+ @entries
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ module Terrestrial
2
+ module Cli
3
+ module TerminalUI
4
+
5
+ def self.show_spinner(fps = 10)
6
+ chars = %w[| / - \\]
7
+ delay = 1.0/fps
8
+ iter = 0
9
+ spinner = Thread.new do
10
+ while iter do # Keep spinning until told otherwise
11
+ print chars[(iter+=1) % chars.length]
12
+ sleep delay
13
+ print "\b"
14
+ print " "
15
+ print "\b"
16
+ end
17
+ end
18
+ yield.tap do # After yielding to the block, save the return value
19
+ iter = false # Tell the thread to exit, cleaning up after itself…
20
+ spinner.join # …and wait for it to do so.
21
+ end # Use the block's return value as the method's
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ module Terrestrial
2
+ module Cli
3
+ class VariableNormalizer
4
+
5
+ def self.run(string, swift: false)
6
+ result = string
7
+ result = format_swift_string(result) if swift
8
+ result = format_string(result)
9
+ end
10
+
11
+ def self.format_swift_string(target_string)
12
+ formatted_string = target_string
13
+ regex = /\\\(.*?\)/
14
+ index = 1
15
+ while formatted_string.scan(regex).any?
16
+ formatted_string = formatted_string.sub(regex, "%#{index}$@")
17
+ index += 1
18
+ end
19
+ formatted_string
20
+ end
21
+
22
+ def self.format_string(target_string)
23
+ formatted_string = target_string
24
+ regex = /\%@/
25
+ index = 1
26
+ while formatted_string.scan(regex).any?
27
+ formatted_string = formatted_string.sub(regex, "%#{index}$@")
28
+ index += 1
29
+ end
30
+ formatted_string
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module Terrestrial
2
+ module Cli
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,82 @@
1
+ require "terrestrial/cli/command"
2
+ require "terrestrial/cli/init"
3
+ require "terrestrial/cli/flight"
4
+ require "terrestrial/cli/scan"
5
+ require "terrestrial/cli/ignite"
6
+ require "terrestrial/cli/push"
7
+ require "terrestrial/cli/pull"
8
+ require "terrestrial/cli/photoshoot"
9
+ require "terrestrial/cli/version"
10
+ require "terrestrial/cli/variable_normalizer"
11
+ require "terrestrial/cli/terminal_ui"
12
+ require "terrestrial/cli/entry_collection_differ"
13
+ require "terrestrial/cli/detects_project_type"
14
+ require "terrestrial/cli/file_picker"
15
+ require "terrestrial/cli/file_finder"
16
+ require "terrestrial/cli/mixpanel_client"
17
+ require "terrestrial/cli/bootstrapper"
18
+ require "terrestrial/cli/android_xml_parser"
19
+ require "terrestrial/cli/android_xml_formatter"
20
+ require "terrestrial/cli/dot_strings_parser"
21
+ require "terrestrial/cli/dot_strings_formatter"
22
+ require "terrestrial/cli/parser"
23
+ require "terrestrial/cli/editor"
24
+ require "terrestrial/cli/engine_mapper"
25
+ require "terrestrial/cli/string_registry"
26
+
27
+ module Terrestrial
28
+ module Cli
29
+
30
+ COMMANDS = ["init", "flight", "pull", "push", "scan", "ignite", "photoshoot"]
31
+
32
+ def self.start(command, opts = {}, args = [])
33
+ case command
34
+ when "init"
35
+ init(opts)
36
+ when "flight"
37
+ flight(opts)
38
+ when "push"
39
+ push(opts)
40
+ when "pull"
41
+ pull(opts)
42
+ when "scan"
43
+ scan(opts)
44
+ when "ignite"
45
+ ignite(opts, args)
46
+ when "photoshoot"
47
+ photoshoot(opts)
48
+ else
49
+ abort "Unknown command #{command}"
50
+ end
51
+ end
52
+
53
+ def self.init(opts)
54
+ Terrestrial::Cli::Init.run(opts)
55
+ end
56
+
57
+ def self.push(opts)
58
+ Terrestrial::Cli::Push.run(opts)
59
+ end
60
+
61
+ def self.pull(opts)
62
+ Terrestrial::Cli::Pull.run(opts)
63
+ end
64
+
65
+ def self.flight(opts)
66
+ Terrestrial::Cli::Flight.run(opts)
67
+ end
68
+
69
+ def self.scan(opts)
70
+ Terrestrial::Cli::Scan.run(opts)
71
+ end
72
+
73
+ def self.ignite(opts, args)
74
+ opts["language"] = args[0]
75
+ Terrestrial::Cli::Ignite.run(opts)
76
+ end
77
+
78
+ def self.photoshoot(opts)
79
+ Terrestrial::Cli::Photoshoot.run(opts)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,99 @@
1
+ module Terrestrial
2
+ module Config
3
+ class << self
4
+
5
+ DEFAULTS = {
6
+ api_url: "https://mission.terrestrial.io",
7
+ directory: Dir.pwd
8
+ }
9
+
10
+ GLOBAL_KEYS = [
11
+ :api_key,
12
+ :user_id
13
+ ]
14
+
15
+ PROJECT_KEYS = [
16
+ :app_id,
17
+ :project_id,
18
+ :platform,
19
+ :translation_files
20
+ ]
21
+
22
+ def load(opts = {})
23
+ values.merge!(opts)
24
+ end
25
+
26
+ def load!(opts = {}, project: true, global: true)
27
+ load(opts)
28
+ _load_project_config if project
29
+ _load_global_config if global
30
+ end
31
+
32
+ def [](key)
33
+ values[key]
34
+ end
35
+
36
+ def reset!
37
+ _reset!
38
+ end
39
+
40
+ def inspect
41
+ "<Terrestrial::Config config=#{values.inspect}>"
42
+ end
43
+
44
+ def project_config_exist?
45
+ File.exists?(_project_config_path)
46
+ end
47
+
48
+ def update_project_config(fail_if_exists: false)
49
+ YamlHelper.update(_project_config_path, values.select {|key, val| PROJECT_KEYS.include? key })
50
+ end
51
+
52
+ def update_global_config
53
+ YamlHelper.update(_global_config_path, values.select {|key, val| GLOBAL_KEYS.include? key })
54
+ end
55
+
56
+ def testing?
57
+ self[:api_url] != DEFAULTS[:api_url]
58
+ end
59
+
60
+ private
61
+
62
+ def _load_project_config
63
+ begin
64
+ values.merge! _project_config
65
+ rescue Errno::ENOENT
66
+ abort "No terrerstrial.yaml found. Are you in the correct folder?"
67
+ end
68
+ end
69
+
70
+ def _load_global_config
71
+ values.merge! _global_config
72
+ end
73
+
74
+ def _reset!
75
+ @values = Hash.new.merge(DEFAULTS)
76
+ end
77
+
78
+ def values
79
+ @values ||= Hash.new.merge(DEFAULTS)
80
+ end
81
+
82
+ def _global_config
83
+ YamlHelper.read _global_config_path
84
+ end
85
+
86
+ def _project_config
87
+ YamlHelper.read _project_config_path
88
+ end
89
+
90
+ def _global_config_path
91
+ Dir.home + "/.terrestrial"
92
+ end
93
+
94
+ def _project_config_path
95
+ Dir.pwd + "/terrestrial.yml"
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,9 @@
1
+ module Terrestrial
2
+ module Cli
3
+ class CreatesTerrestrialYml
4
+
5
+ def self.run(project_id, app_id, project_type)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module Terrestrial
2
+ class Web
3
+ class Response
4
+ def initialize(http_response)
5
+ @inner_response = http_response
6
+ end
7
+
8
+ def success?
9
+ @inner_response.code.to_s.start_with?("2")
10
+ end
11
+
12
+ def body
13
+ JSON.parse(@inner_response.body)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,78 @@
1
+ require 'terrestrial/web/response'
2
+ require 'net/http'
3
+ require 'json'
4
+
5
+ module Terrestrial
6
+ class Web
7
+
8
+ def initialize(api_token = nil)
9
+ @url = URI.parse(Config[:api_url])
10
+ @token = api_token || token
11
+ end
12
+
13
+ def push(project_id, app_id, strings_and_context)
14
+ post("projects/#{project_id}/apps/#{app_id}/imports",
15
+ {
16
+ import: {
17
+ entries: strings_and_context
18
+ }
19
+ })
20
+ end
21
+
22
+ def create_app(project_id, platform)
23
+ post("projects/#{project_id}/apps",
24
+ {
25
+ app: {
26
+ platform: platform
27
+ }
28
+ })
29
+ end
30
+
31
+ def get_app_strings(project_id, app_id)
32
+ get("projects/#{project_id}/apps/#{app_id}/strings")
33
+ end
34
+
35
+ def get_translations(project_id, app_id)
36
+ get("projects/#{project_id}/apps/#{app_id}/translations")
37
+ end
38
+
39
+ def get_profile
40
+ get("me")
41
+ end
42
+
43
+ private
44
+
45
+ def post(path, payload)
46
+ http = Net::HTTP.new(@url.host, @url.port)
47
+ http.use_ssl = true if @url.scheme == "https"
48
+
49
+ request = Net::HTTP::Post.new(base_url + path)
50
+ request.body = payload.to_json
51
+ request["Content-Type"] = "application/json"
52
+ request["AUTHENTICATE"] = @token
53
+
54
+ Response.new(http.request(request))
55
+ end
56
+
57
+ def get(path)
58
+ http = Net::HTTP.new(@url.host, @url.port)
59
+ http.use_ssl = true if @url.scheme == "https"
60
+
61
+ request = Net::HTTP::Get.new(base_url + path)
62
+ request["Content-Type"] = "application/json"
63
+ request["AUTHENTICATE"] = @token
64
+
65
+ Response.new(http.request(request))
66
+ end
67
+
68
+ def base_url
69
+ @url.request_uri
70
+ end
71
+
72
+ private
73
+
74
+ def token
75
+ Config[:api_key]
76
+ end
77
+ end
78
+ end