textflight-client 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|