textflight-client 1.0.1
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 +7 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +4 -0
- data/LICENSE.md +675 -0
- data/README.md +160 -0
- data/Rakefile +29 -0
- data/bin/client.rb +291 -0
- data/lib/textflight-client.rb +33 -0
- data/lib/textflight-client/command_parser.rb +42 -0
- data/lib/textflight-client/dot_dir.rb +21 -0
- data/lib/textflight-client/environment.rb +55 -0
- data/lib/textflight-client/logging.rb +58 -0
- data/lib/textflight-client/models/local.rb +69 -0
- data/lib/textflight-client/models/model.rb +55 -0
- data/lib/textflight-client/models/nav.rb +293 -0
- data/lib/textflight-client/models/scan.rb +222 -0
- data/lib/textflight-client/models/status.rb +191 -0
- data/lib/textflight-client/models/status_report.rb +26 -0
- data/lib/textflight-client/response_parser.rb +200 -0
- data/lib/textflight-client/string_utils.rb +15 -0
- data/lib/textflight-client/tfprompt.rb +30 -0
- data/lib/textflight-client/version.rb +3 -0
- metadata +325 -0
@@ -0,0 +1,222 @@
|
|
1
|
+
|
2
|
+
module TFClient
|
3
|
+
module Models
|
4
|
+
|
5
|
+
class Scan < Response
|
6
|
+
LINE_IDENTIFIERS = [
|
7
|
+
"Owner",
|
8
|
+
"Operators",
|
9
|
+
"Outfit space",
|
10
|
+
"Shield charge",
|
11
|
+
"Outfits",
|
12
|
+
"Cargo"
|
13
|
+
]
|
14
|
+
|
15
|
+
attr_reader :id, :name, :owner, :outfit_space, :shield_charge
|
16
|
+
attr_reader :outfits, :cargo
|
17
|
+
|
18
|
+
def initialize(lines:)
|
19
|
+
super(lines: lines)
|
20
|
+
|
21
|
+
ship_line = lines[0]
|
22
|
+
values_hash = ResponseParser.hash_from_line_values(line: ship_line)
|
23
|
+
@id = values_hash[:id].to_i
|
24
|
+
@name = values_hash[:name]
|
25
|
+
|
26
|
+
LINE_IDENTIFIERS.each do |line_id|
|
27
|
+
|
28
|
+
# Not sure what value this adds
|
29
|
+
next if line_id == "Operators"
|
30
|
+
|
31
|
+
var_name = ResponseParser.snake_case_sym_from_string(string: line_id)
|
32
|
+
class_name = ResponseParser.camel_case_from_string(string: line_id)
|
33
|
+
clazz = ResponseParser.model_class_from_string(string: class_name)
|
34
|
+
|
35
|
+
if clazz.nil?
|
36
|
+
raise "could not find class name: #{class_name} derived from #{line_id}"
|
37
|
+
end
|
38
|
+
|
39
|
+
line, _ = ResponseParser.line_and_index_for_beginning_with(lines: @lines,
|
40
|
+
string: line_id)
|
41
|
+
|
42
|
+
if ["Owner", "Outfit space", "Shield charge"].include?(line_id)
|
43
|
+
var = clazz.new(line: line)
|
44
|
+
elsif ["Outfits", "Cargo"].include?(line_id)
|
45
|
+
var = clazz.new(lines: @lines)
|
46
|
+
if var.is_a?(TFClient::Models::Outfits)
|
47
|
+
var.max_slots = @outfit_space.value
|
48
|
+
end
|
49
|
+
else
|
50
|
+
raise "Cannot find class initializer for: #{line_id}"
|
51
|
+
end
|
52
|
+
|
53
|
+
instance_variable_set("@#{var_name}", var)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def response
|
58
|
+
# TODO this is interesting only when you scan _other_ structures
|
59
|
+
# table = TTY::Table.new(header: [
|
60
|
+
# {value: @owner.translation, alignment: :center},
|
61
|
+
# {value: @outfit_space.translation, alignment: :center},
|
62
|
+
# {value: @shield_charge.translation, alignment: :center}
|
63
|
+
# ])
|
64
|
+
#
|
65
|
+
# table << [@owner.username,
|
66
|
+
# @outfit_space.value,
|
67
|
+
# @shield_charge.value]
|
68
|
+
#
|
69
|
+
# puts table.render(:ascii, padding: [0,1,0,1],
|
70
|
+
# width: Models::TABLE_WIDTH, resize: true) do |renderer|
|
71
|
+
# renderer.alignments= [:center, :center, :center]
|
72
|
+
# end
|
73
|
+
|
74
|
+
puts @outfits.to_s
|
75
|
+
puts @cargo.to_s
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Owner < Model
|
80
|
+
attr_reader :username
|
81
|
+
|
82
|
+
def initialize(line:)
|
83
|
+
super(line: line)
|
84
|
+
@username = @values_hash[:username]
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_s
|
88
|
+
"#{@translation}: #{@username}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class OutfitSpace < Model
|
93
|
+
attr_reader :value
|
94
|
+
|
95
|
+
def initialize(line:)
|
96
|
+
super(line: line)
|
97
|
+
@value = @values_hash[:space].to_i
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_s
|
101
|
+
"#{@translation}: #{@value}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class ShieldCharge < Model
|
106
|
+
attr_reader :value
|
107
|
+
|
108
|
+
def initialize(line:)
|
109
|
+
super(line: line)
|
110
|
+
@value = @values_hash[:charge].to_f
|
111
|
+
end
|
112
|
+
|
113
|
+
def to_s
|
114
|
+
"#{@translation}: #{@value}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class Outfits < ModelWithItems
|
119
|
+
|
120
|
+
attr_accessor :max_slots
|
121
|
+
|
122
|
+
def initialize(lines:)
|
123
|
+
line, index = ResponseParser.line_and_index_for_beginning_with(lines: lines,
|
124
|
+
string: "Outfits")
|
125
|
+
super(line: line)
|
126
|
+
|
127
|
+
items = ResponseParser.collect_list_items(lines: lines, start_index: index + 1)
|
128
|
+
@items = items.map do |item|
|
129
|
+
line = item.strip
|
130
|
+
|
131
|
+
hash = ResponseParser.hash_from_line_values(line: line)
|
132
|
+
|
133
|
+
index = hash[:index].to_i
|
134
|
+
name = hash[:name]
|
135
|
+
mark = hash[:mark].to_i
|
136
|
+
setting = hash[:setting].to_i
|
137
|
+
{ index: index, name: name, mark: mark, setting: setting}
|
138
|
+
end
|
139
|
+
@max_slots = 0
|
140
|
+
end
|
141
|
+
|
142
|
+
def to_s
|
143
|
+
table = TTY::Table.new(header: [
|
144
|
+
"#{@translation}: #{slots_used}/#{@max_slots} slots",
|
145
|
+
{value: "name", alignment: :center},
|
146
|
+
{value: "setting", alignment: :center},
|
147
|
+
{value: "index", alignment: :center}
|
148
|
+
])
|
149
|
+
|
150
|
+
@items.each do |item|
|
151
|
+
table << [
|
152
|
+
"[#{item[:index]}]",
|
153
|
+
"#{item[:name]} (#{item[:mark].to_roman})",
|
154
|
+
item[:setting],
|
155
|
+
"[#{item[:index]}]"
|
156
|
+
]
|
157
|
+
end
|
158
|
+
|
159
|
+
table.render(:ascii, Models::TABLE_OPTIONS) do |renderer|
|
160
|
+
renderer.alignments= [:right, :right, :center, :center]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def slots_used
|
165
|
+
@items.map { |hash| hash[:mark] }.sum
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class Cargo < ModelWithItems
|
170
|
+
|
171
|
+
def initialize(lines:)
|
172
|
+
line, index = ResponseParser.line_and_index_for_beginning_with(lines: lines,
|
173
|
+
string: "Cargo")
|
174
|
+
super(line: line)
|
175
|
+
|
176
|
+
items = ResponseParser.collect_list_items(lines: lines, start_index: index + 1)
|
177
|
+
@items = items.map do |item|
|
178
|
+
line = item.strip
|
179
|
+
|
180
|
+
hash = ResponseParser.hash_from_line_values(line: line)
|
181
|
+
|
182
|
+
index = hash[:index].to_i
|
183
|
+
name = hash[:name]
|
184
|
+
count = hash[:count].to_i
|
185
|
+
# TODO: this must be the mark?
|
186
|
+
mark = hash[:extra].to_i
|
187
|
+
{ index: index, name: name, count: count, mark: mark}
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def to_s
|
192
|
+
table = TTY::Table.new(header: [
|
193
|
+
"Weight: #{weight}",
|
194
|
+
{value: "cargo", alignment: :center},
|
195
|
+
{value: "amount", alignment: :center},
|
196
|
+
{value: "index", alignment: :center}
|
197
|
+
])
|
198
|
+
|
199
|
+
@items.each do |item|
|
200
|
+
name = item[:name]
|
201
|
+
mark = item[:mark].to_i
|
202
|
+
if mark && (mark != 0)
|
203
|
+
name = "#{name} (#{mark.to_roman})"
|
204
|
+
end
|
205
|
+
table << ["[#{item[:index]}]",
|
206
|
+
name,
|
207
|
+
item[:count],
|
208
|
+
"[#{item[:index]}]"]
|
209
|
+
end
|
210
|
+
|
211
|
+
table.render(:ascii, Models::TABLE_OPTIONS) do |renderer|
|
212
|
+
renderer.alignments= [:right, :right, :center, :center]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# TODO: only some items in the inventory contribute to weight
|
217
|
+
def weight
|
218
|
+
@items.map { |hash| hash[:count] }.sum
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
|
2
|
+
module TFClient
|
3
|
+
module Models
|
4
|
+
|
5
|
+
class Status < Response
|
6
|
+
|
7
|
+
# returns 2 values
|
8
|
+
def self.status_from_lines(lines:, start_with:)
|
9
|
+
stripped = lines.map { |line| line.strip }
|
10
|
+
prefix = start_with.strip
|
11
|
+
line, _ = ResponseParser.line_and_index_for_beginning_with(lines: stripped,
|
12
|
+
string: prefix)
|
13
|
+
if !lines || !line.start_with?(prefix)
|
14
|
+
raise "expected line to be a status line for #{prefix} in #{lines}"
|
15
|
+
end
|
16
|
+
|
17
|
+
tokens = ResponseParser.tokenize_line(line: line)
|
18
|
+
|
19
|
+
status = tokens[0].split(": ").last
|
20
|
+
|
21
|
+
case status
|
22
|
+
when "Overheat in {remaining} seconds!"
|
23
|
+
status = "Overheating"
|
24
|
+
when "OVERHEATED"
|
25
|
+
status = "Overheated"
|
26
|
+
when "Ready to engage"
|
27
|
+
status = "Ready"
|
28
|
+
when "Charging ({charge}%)"
|
29
|
+
status = "Charging"
|
30
|
+
when "FAILED"
|
31
|
+
status = "Failed"
|
32
|
+
when "BROWNOUT"
|
33
|
+
status = "Brownout"
|
34
|
+
when "OVERLOADED"
|
35
|
+
status = "Overloaded"
|
36
|
+
when "Brownout in {remaining} seconds!"
|
37
|
+
status = "Overloaded"
|
38
|
+
when "Regenerating at {rate}/s ({shield}/{max})"
|
39
|
+
status = "Regenerating"
|
40
|
+
when "{progress}% ({interval} second interval)"
|
41
|
+
status = "Online"
|
42
|
+
end
|
43
|
+
|
44
|
+
translation = tokens[1]
|
45
|
+
|
46
|
+
return status, translation if tokens.size == 2
|
47
|
+
|
48
|
+
translation = ResponseParser.substitute_line_values(line: line)
|
49
|
+
|
50
|
+
return status, translation.strip
|
51
|
+
end
|
52
|
+
|
53
|
+
attr_reader :states
|
54
|
+
attr_reader :status_report
|
55
|
+
attr_reader :mass, :total_outfit_space, :used_outfit_space
|
56
|
+
attr_reader :heat, :max_heat, :heat_rate, :cooling_status
|
57
|
+
attr_reader :energy, :max_energy, :energy_rate, :power_status
|
58
|
+
attr_reader :antigravity_engine_status, :antigravity
|
59
|
+
attr_reader :mining_status, :mining_interval, :mining_power
|
60
|
+
attr_reader :engine_status, :warp_charge
|
61
|
+
attr_reader :shield_status, :shield_max, :shield, :shield_charge_rate
|
62
|
+
attr_reader :colonists, :colonists_status
|
63
|
+
|
64
|
+
def initialize(lines:)
|
65
|
+
super(lines: lines)
|
66
|
+
|
67
|
+
@states = {}
|
68
|
+
|
69
|
+
@status_report = Models::StatusReport.new(lines: lines)
|
70
|
+
@mass = @status_report.hash[:mass].to_i
|
71
|
+
@total_outfit_space = @status_report.hash[:total_outfit_space].to_i
|
72
|
+
|
73
|
+
outfit_space_line = lines.detect do |line|
|
74
|
+
line.strip.start_with?("Outfit space")
|
75
|
+
end
|
76
|
+
|
77
|
+
hash = ResponseParser.hash_from_line_values(line: outfit_space_line)
|
78
|
+
@used_outfit_space = @total_outfit_space - hash[:space].to_i
|
79
|
+
|
80
|
+
# Cooling
|
81
|
+
@states[:cooling], @cooling_status = Status.status_from_lines(
|
82
|
+
lines: lines,
|
83
|
+
start_with: "Cooling status")
|
84
|
+
@heat = @status_report.hash[:heat].to_i
|
85
|
+
@max_heat = @status_report.hash[:max_heat].to_i
|
86
|
+
@heat_rate = @status_report.hash[:heat_rate].to_f
|
87
|
+
|
88
|
+
# Energy / Power
|
89
|
+
@states[:power], @power_status = Status.status_from_lines(
|
90
|
+
lines: lines,
|
91
|
+
start_with: "Power status"
|
92
|
+
)
|
93
|
+
|
94
|
+
@energy = @status_report.hash[:energy].to_i
|
95
|
+
@max_energy = @status_report.hash[:max_energy].to_i
|
96
|
+
@energy_rate = @status_report.hash[:energy_rate].to_f
|
97
|
+
|
98
|
+
# Antigravity
|
99
|
+
antigravity_line = lines.detect do |line|
|
100
|
+
line.strip.start_with?("Antigravity engines")
|
101
|
+
end
|
102
|
+
|
103
|
+
if antigravity_line
|
104
|
+
@states[:antigravity], @antigravity_engine_status =
|
105
|
+
Status.status_from_lines(lines: lines, start_with: "Antigravity engines")
|
106
|
+
@antigravity = @status_report.hash[:antigravity].to_i
|
107
|
+
else
|
108
|
+
# Needs translation
|
109
|
+
@states[:antigravity] = "Offline"
|
110
|
+
@antigravity = "Antigravity engines: Offline"
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
# Mining
|
116
|
+
mining_progress_line = lines.detect do |line|
|
117
|
+
line.strip.start_with?("Mining progress")
|
118
|
+
end
|
119
|
+
|
120
|
+
if mining_progress_line
|
121
|
+
@states[:mining], @mining_status =
|
122
|
+
Status.status_from_lines(lines: lines,
|
123
|
+
start_with: "Mining progress")
|
124
|
+
hash = ResponseParser.hash_from_line_values(line: mining_progress_line)
|
125
|
+
@mining_interval = hash[:interval].to_f
|
126
|
+
@mining_power = @status_report.hash[:mining_power].to_f
|
127
|
+
else
|
128
|
+
@mining_interval = nil
|
129
|
+
@mining_power = nil
|
130
|
+
# TODO needs a translation
|
131
|
+
@states[:mining] = "Offline"
|
132
|
+
@mining_status = "Offline"
|
133
|
+
end
|
134
|
+
|
135
|
+
# Warp
|
136
|
+
warp_line = lines.detect do |line|
|
137
|
+
line.strip.start_with?("Warp engines")
|
138
|
+
end
|
139
|
+
if warp_line
|
140
|
+
@states[:warp], @engine_status =
|
141
|
+
Status.status_from_lines(lines: lines,
|
142
|
+
start_with: "Warp engines")
|
143
|
+
@warp_charge = @status_report.hash[:warp_charge].to_f
|
144
|
+
else
|
145
|
+
@states[:warp] = "Offline"
|
146
|
+
@warp_charge = 0.0
|
147
|
+
end
|
148
|
+
|
149
|
+
# Shield
|
150
|
+
shield_status_line = lines.detect do |line|
|
151
|
+
line.strip.start_with?("Shields")
|
152
|
+
end
|
153
|
+
|
154
|
+
if shield_status_line
|
155
|
+
@states[:shields], @shield_status =
|
156
|
+
Status.status_from_lines(lines: lines,
|
157
|
+
start_with: "Shields")
|
158
|
+
@shield_charge_rate = @status_report.hash[:shield_rate].to_f
|
159
|
+
@shield_max = @status_report.hash[:max_shield].to_f
|
160
|
+
@shield = @status_report.hash[:shield].to_f
|
161
|
+
else
|
162
|
+
# TODO Need translation
|
163
|
+
@shield_status = "Offline"
|
164
|
+
@states[:shields] = "Offline"
|
165
|
+
@shield_charge_rate = nil
|
166
|
+
@shield_max = @status_report.hash[:max_shield].to_f
|
167
|
+
@shield = 0
|
168
|
+
end
|
169
|
+
|
170
|
+
# Colonists
|
171
|
+
colonists_line = lines.detect do |line|
|
172
|
+
line.strip.start_with?("Colonists")
|
173
|
+
end
|
174
|
+
|
175
|
+
if colonists_line
|
176
|
+
# TODO Need translation
|
177
|
+
@states[:colonists] = "Crewed"
|
178
|
+
@colonists_status =
|
179
|
+
ResponseParser.substitute_line_values(line: colonists_line)
|
180
|
+
hash = ResponseParser.hash_from_line_values(line: colonists_line)
|
181
|
+
@colonists = hash[:crew].to_i
|
182
|
+
else
|
183
|
+
# TODO Need translation
|
184
|
+
@states[:colonists] = "Unmanned"
|
185
|
+
@colonists_status = "Unmanned"
|
186
|
+
@colonists = 0
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
module TFClient
|
3
|
+
module Models
|
4
|
+
|
5
|
+
STATUS_BEGIN = "STATUSREPORT BEGIN".freeze
|
6
|
+
STATUS_END = "STATUSREPORT END".freeze
|
7
|
+
|
8
|
+
class StatusReport
|
9
|
+
|
10
|
+
attr_reader :hash
|
11
|
+
|
12
|
+
def initialize(lines:)
|
13
|
+
if lines[0] != STATUS_BEGIN
|
14
|
+
raise "Expected lines[0] to be == #{STATUS_BEGIN}, found: #{lines[0]}"
|
15
|
+
end
|
16
|
+
|
17
|
+
@hash = {}
|
18
|
+
lines.each do |line|
|
19
|
+
break if line == STATUS_END
|
20
|
+
tokens = line.strip.split(": ")
|
21
|
+
@hash[tokens[0].to_sym] = tokens[1]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
|
2
|
+
module TFClient
|
3
|
+
class ResponseParser
|
4
|
+
|
5
|
+
FIELD_DELIMITER = "|".freeze
|
6
|
+
VARIABLE_REGEX = /(\{[a-z_]+\}+)/.freeze
|
7
|
+
|
8
|
+
def self.substitute_line_values(line:)
|
9
|
+
return line.chomp if !line[/\|/]
|
10
|
+
tokens = line.chomp.split("|")
|
11
|
+
|
12
|
+
translation = tokens[1]
|
13
|
+
|
14
|
+
matches = translation.scan(VARIABLE_REGEX)
|
15
|
+
|
16
|
+
return translation if matches.empty?
|
17
|
+
|
18
|
+
values = self.hash_from_line_values(line: line.chomp)
|
19
|
+
|
20
|
+
with_substitutes = translation.chomp
|
21
|
+
|
22
|
+
matches.each do |match|
|
23
|
+
key = match[0].sub("{", "").sub("}", "").to_sym
|
24
|
+
with_substitutes.gsub!(match[0], values[key])
|
25
|
+
end
|
26
|
+
|
27
|
+
with_substitutes
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.substitute_values(lines:)
|
31
|
+
lines.map do |line|
|
32
|
+
self.substitute_line_values(line:line.chomp)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.tokenize_line(line:)
|
37
|
+
lines = line.split(FIELD_DELIMITER)
|
38
|
+
stripped = []
|
39
|
+
lines.each_with_index do |line, index|
|
40
|
+
if index == 0
|
41
|
+
stripped << line
|
42
|
+
else
|
43
|
+
stripped << line.strip
|
44
|
+
end
|
45
|
+
end
|
46
|
+
stripped
|
47
|
+
end
|
48
|
+
|
49
|
+
# returns two values
|
50
|
+
def self.line_and_index_for_beginning_with(lines:, string:)
|
51
|
+
lines.each_with_index do |line, index|
|
52
|
+
return line.chomp, index if line.start_with?(string)
|
53
|
+
end
|
54
|
+
return nil, -1
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns a hash of the key=value pairs found at the end of lines
|
58
|
+
def self.hash_from_line_values(line:)
|
59
|
+
tokens = self.tokenize_line(line: line)[2..-1]
|
60
|
+
hash = {}
|
61
|
+
tokens.each do |token|
|
62
|
+
key_value = token.split("=")
|
63
|
+
hash[key_value[0].to_sym] = key_value[1]
|
64
|
+
end
|
65
|
+
hash
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.is_list_item?(line:)
|
69
|
+
if line && line.length != 0 && line.start_with?("\t")
|
70
|
+
true
|
71
|
+
else
|
72
|
+
false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.collect_list_items(lines:, start_index:)
|
77
|
+
items = []
|
78
|
+
index = start_index
|
79
|
+
loop do
|
80
|
+
line = lines[index]
|
81
|
+
if self.is_list_item?(line: line)
|
82
|
+
items << line.strip
|
83
|
+
index = index + 1
|
84
|
+
else
|
85
|
+
break
|
86
|
+
end
|
87
|
+
end
|
88
|
+
items
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.label_and_translation(tokens:)
|
92
|
+
if tokens[0][/Claimed by/]
|
93
|
+
{label: "Claimed by", translation: tokens[1].split("'")[0].strip}
|
94
|
+
else
|
95
|
+
{label: tokens[0].split(":")[0], translation: tokens[1].split(":")[0] }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.camel_case_from_string(string:)
|
100
|
+
string.split(" ").map do |token|
|
101
|
+
token.capitalize
|
102
|
+
end.join("")
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.snake_case_sym_from_string(string:)
|
106
|
+
string.split(" ").map do |token|
|
107
|
+
token.downcase
|
108
|
+
end.join("_").to_sym
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.model_class_from_string(string:)
|
112
|
+
if !TFClient::Models.constants.include?(string.to_sym)
|
113
|
+
return nil
|
114
|
+
end
|
115
|
+
|
116
|
+
"TFClient::Models::#{string}".split("::").reduce(Object) do |obj, cls|
|
117
|
+
obj.const_get(cls)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
attr_reader :command
|
122
|
+
attr_reader :textflight_command
|
123
|
+
attr_reader :response
|
124
|
+
attr_reader :lines
|
125
|
+
|
126
|
+
def initialize(command:, textflight_command:, response:)
|
127
|
+
@command = command
|
128
|
+
@textflight_command = textflight_command
|
129
|
+
@response = response
|
130
|
+
end
|
131
|
+
|
132
|
+
def parse
|
133
|
+
@lines = @response.lines(chomp: true).reject { |line| line.length == 0 }
|
134
|
+
case @textflight_command
|
135
|
+
when "nav"
|
136
|
+
parse_nav(command: @command)
|
137
|
+
when "scan"
|
138
|
+
parse_scan
|
139
|
+
when "status"
|
140
|
+
parse_status(command: @command)
|
141
|
+
else
|
142
|
+
if @response[/#{Models::STATUS_BEGIN}/]
|
143
|
+
@response = @lines[0].chomp
|
144
|
+
@lines = [@response]
|
145
|
+
end
|
146
|
+
|
147
|
+
puts ResponseParser.substitute_values(lines: @lines).join("\n")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def parse_nav(command:)
|
152
|
+
nav = TFClient::Models::Nav.new(lines: lines)
|
153
|
+
if command != "nav-for-prompt"
|
154
|
+
puts nav.response
|
155
|
+
end
|
156
|
+
nav
|
157
|
+
end
|
158
|
+
|
159
|
+
def parse_scan
|
160
|
+
scan = TFClient::Models::Scan.new(lines: lines)
|
161
|
+
puts scan.response
|
162
|
+
scan
|
163
|
+
end
|
164
|
+
|
165
|
+
def parse_status(command:)
|
166
|
+
if command == "status-for-prompt"
|
167
|
+
TFClient::Models::Status.new(lines: lines)
|
168
|
+
else
|
169
|
+
_, index_start =
|
170
|
+
ResponseParser.line_and_index_for_beginning_with(
|
171
|
+
lines: @lines,
|
172
|
+
string: Models::STATUS_BEGIN
|
173
|
+
)
|
174
|
+
if index_start == -1
|
175
|
+
puts ResponseParser.substitute_values(lines: @lines).join("\n")
|
176
|
+
end
|
177
|
+
|
178
|
+
_, index_end =
|
179
|
+
ResponseParser.line_and_index_for_beginning_with(
|
180
|
+
lines: @lines,
|
181
|
+
string: Models::STATUS_END
|
182
|
+
)
|
183
|
+
|
184
|
+
if index_start != 0
|
185
|
+
lines_before_status = @lines[0..index_start - 1]
|
186
|
+
puts ResponseParser.substitute_values(
|
187
|
+
lines: lines_before_status
|
188
|
+
).join("\n")
|
189
|
+
else
|
190
|
+
lines_after_status = @lines[index_end + 1..-1]
|
191
|
+
puts ResponseParser.substitute_values(
|
192
|
+
lines: lines_after_status
|
193
|
+
).join("\n")
|
194
|
+
|
195
|
+
Models::StatusReport.new(lines: @lines[index_start...index_end])
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|