da_funk 0.5.4 → 0.6.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 +4 -4
- data/Gemfile.lock +4 -4
- data/README.md +159 -81
- data/RELEASE_NOTES.md +19 -0
- data/Rakefile +6 -0
- data/lib/da_funk/callback_flow.rb +50 -0
- data/lib/da_funk/file_parameter.rb +70 -0
- data/lib/da_funk/helper.rb +100 -35
- data/lib/da_funk/i18n.rb +77 -0
- data/lib/da_funk/i18n_error.rb +3 -0
- data/lib/da_funk/iso8583.rb +1 -0
- data/lib/da_funk/rake_task.rb +7 -1
- data/lib/da_funk/screen_flow.rb +30 -0
- data/lib/device.rb +1 -1
- data/lib/device/application.rb +75 -17
- data/lib/device/crypto.rb +2 -1
- data/lib/device/io.rb +5 -2
- data/lib/device/network.rb +12 -3
- data/lib/device/notification.rb +3 -3
- data/lib/device/params_dat.rb +102 -34
- data/lib/device/printer.rb +1 -1
- data/lib/device/setting.rb +6 -1
- data/lib/device/transaction/download.rb +11 -5
- data/lib/device/version.rb +1 -1
- data/lib/ext/string.rb +6 -0
- data/lib/file_db.rb +7 -3
- data/lib/iso8583/bitmap.rb +3 -6
- data/lib/iso8583/file_parser.rb +8 -10
- data/lib/iso8583/message.rb +9 -9
- data/lib/zip.rb +3 -3
- data/test/resources/shared/bitmap.dat +128 -0
- data/test/unit/iso8583_build_klass.rb +44 -0
- metadata +11 -2
data/lib/da_funk/helper.rb
CHANGED
@@ -16,46 +16,45 @@ module DaFunk
|
|
16
16
|
|
17
17
|
def attach
|
18
18
|
Device::Display.clear
|
19
|
-
|
19
|
+
I18n.pt(:attach_connecting)
|
20
20
|
if Device::Network.connected? < 0
|
21
21
|
if (ret = Device::Network.attach) == 0
|
22
|
-
|
22
|
+
I18n.pt(:attach_connected)
|
23
23
|
else
|
24
|
-
|
24
|
+
I18n.pt(:attach_fail, :args => [ret.to_s])
|
25
25
|
sleep 4
|
26
26
|
return false
|
27
27
|
end
|
28
28
|
else
|
29
|
-
|
29
|
+
I18n.pt(:attach_already_connected)
|
30
30
|
end
|
31
31
|
true
|
32
32
|
end
|
33
33
|
|
34
|
-
# TODO Add i18n or something
|
35
34
|
def check_download_error(ret)
|
36
35
|
value = true
|
37
36
|
case ret
|
38
37
|
when Device::Transaction::Download::SERIAL_NUMBER_NOT_FOUND
|
39
|
-
|
38
|
+
I18n.pt(:download_serial_number_not_found, :args => [ret])
|
40
39
|
value = false
|
41
40
|
when Device::Transaction::Download::FILE_NOT_FOUND
|
42
|
-
|
41
|
+
I18n.pt(:download_file_not_found, :args => [ret])
|
43
42
|
value = false
|
44
43
|
when Device::Transaction::Download::FILE_NOT_CHANGE
|
45
|
-
|
44
|
+
I18n.pt(:download_file_is_the_same, :args => [ret])
|
46
45
|
when Device::Transaction::Download::SUCCESS
|
47
|
-
|
46
|
+
I18n.pt(:download_success, :args => [ret])
|
48
47
|
when Device::Transaction::Download::COMMUNICATION_ERROR
|
49
|
-
|
48
|
+
I18n.pt(:download_communication_failure, :args => [ret])
|
50
49
|
value = false
|
51
50
|
when Device::Transaction::Download::MAPREDUCE_RESPONSE_ERROR
|
52
|
-
|
51
|
+
I18n.pt(:download_encoding_error, :args => [ret])
|
53
52
|
value = false
|
54
53
|
when Device::Transaction::Download::IO_ERROR
|
55
|
-
|
54
|
+
I18n.pt(:download_io_error, :args => [ret])
|
56
55
|
value = false
|
57
56
|
else
|
58
|
-
|
57
|
+
I18n.pt(:download_communication_failure, :args => [ret])
|
59
58
|
value = false
|
60
59
|
end
|
61
60
|
|
@@ -72,6 +71,17 @@ module DaFunk
|
|
72
71
|
ret
|
73
72
|
end
|
74
73
|
|
74
|
+
def try_key(keys, timeout = Device::IO.timeout)
|
75
|
+
key = nil
|
76
|
+
keys = [keys].flatten
|
77
|
+
time = Time.now + timeout / 1000 if (timeout != 0)
|
78
|
+
while (! keys.include?(key)) do
|
79
|
+
return Device::IO::KEY_TIMEOUT if (timeout != 0 && time < Time.now)
|
80
|
+
key = getc(timeout)
|
81
|
+
end
|
82
|
+
key
|
83
|
+
end
|
84
|
+
|
75
85
|
# Create a form menu.
|
76
86
|
#
|
77
87
|
# @param title [String] Text to display on line 0. If nil title won't be
|
@@ -98,26 +108,86 @@ module DaFunk
|
|
98
108
|
# menu("Option menu", selection, options)
|
99
109
|
#
|
100
110
|
def menu(title, selection, options = {})
|
101
|
-
|
111
|
+
return nil if selection.empty?
|
112
|
+
options[:number] = true if options[:number].nil?
|
113
|
+
options[:timeout] ||= Device::IO.timeout
|
114
|
+
key, selected = pagination(title, options, selection) do |collection, line_zero|
|
115
|
+
collection.each_with_index do |value,i|
|
116
|
+
display = value.is_a?(Array) ? value[0] : value
|
117
|
+
if options[:number]
|
118
|
+
Device::Display.print("#{i+1} #{display}", i+line_zero, 0)
|
119
|
+
else
|
120
|
+
Device::Display.print("#{display}", i+line_zero, 0)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
102
124
|
|
103
|
-
if
|
104
|
-
|
105
|
-
|
125
|
+
if key == Device::IO::ENTER || key == Device::IO::CANCEL
|
126
|
+
options[:default]
|
127
|
+
else
|
128
|
+
selected
|
106
129
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
130
|
+
end
|
131
|
+
|
132
|
+
# TODO Scalone: Refactor.
|
133
|
+
def pagination(title, options, collection, &block)
|
134
|
+
if title.nil?
|
135
|
+
start_line = 0
|
136
|
+
options[:limit] ||= STDOUT.max_y
|
137
|
+
else
|
138
|
+
start_line = 1
|
139
|
+
options[:limit] ||= STDOUT.max_y - 1
|
140
|
+
end
|
141
|
+
if collection.size > options[:limit] # minus header
|
142
|
+
key = Device::IO::F1
|
143
|
+
pages = pagination_page(collection, options[:limit] - 1)
|
144
|
+
page = 1
|
145
|
+
while(key == Device::IO::F1 || key == Device::IO::F2)
|
146
|
+
Device::Display.clear
|
147
|
+
print_title(title, options[:default]) if title
|
148
|
+
Device::Display.print("< F1 ____ #{page}/#{pages.size} ____ F2 >", start_line, 0)
|
149
|
+
values = pages[page].to_a
|
150
|
+
block.call(values, start_line+1)
|
151
|
+
key = try_key(pagination_keys(values.size))
|
152
|
+
page = pagination_key_page(page, key, pages.size)
|
114
153
|
end
|
154
|
+
else
|
155
|
+
Device::Display.clear
|
156
|
+
print_title(title, options[:default]) if title
|
157
|
+
values = collection.to_a
|
158
|
+
block.call(values, start_line)
|
159
|
+
key = try_key(pagination_keys(collection.size))
|
160
|
+
end
|
161
|
+
result = values[key.to_i-1] if key.integer?
|
162
|
+
if result.is_a? Array
|
163
|
+
[key, result[1]]
|
164
|
+
else
|
165
|
+
[key, result]
|
115
166
|
end
|
167
|
+
end
|
116
168
|
|
117
|
-
|
169
|
+
def pagination_key_page(page, key, size)
|
170
|
+
if key == Device::IO::F1
|
171
|
+
page == 1 ? page : page -= 1
|
172
|
+
elsif key == Device::IO::F2
|
173
|
+
page >= size ? size : page += 1
|
174
|
+
end
|
175
|
+
end
|
118
176
|
|
119
|
-
|
120
|
-
|
177
|
+
def pagination_page(values, size)
|
178
|
+
page = 1
|
179
|
+
i = 0
|
180
|
+
values.group_by do |value|
|
181
|
+
if size < (i+=1)
|
182
|
+
page+=1; i=0
|
183
|
+
end
|
184
|
+
page
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def pagination_keys(size)
|
189
|
+
(1..size.to_i).to_a.map(&:to_s) + [Device::IO::ENTER, Device::IO::CLEAR,
|
190
|
+
Device::IO::CANCEL, Device::IO::F1, Device::IO::F2]
|
121
191
|
end
|
122
192
|
|
123
193
|
def number_to_currency(value, options = {})
|
@@ -146,12 +216,7 @@ module DaFunk
|
|
146
216
|
text << ch
|
147
217
|
text << options[:delimiter] if (i % 3 == 0) && (len - unit.size) != i
|
148
218
|
end
|
149
|
-
|
150
|
-
if options[:label]
|
151
|
-
options[:label] + currency
|
152
|
-
else
|
153
|
-
currency
|
154
|
-
end
|
219
|
+
[rjust(text.reverse, 1, "0"),rjust(unit, options[:precision], "0")].join options[:separator]
|
155
220
|
end
|
156
221
|
|
157
222
|
def ljust(string, size, new_string)
|
@@ -183,9 +248,9 @@ module DaFunk
|
|
183
248
|
|
184
249
|
def print_title(string, default)
|
185
250
|
if default
|
186
|
-
puts("#{string} (#{default})
|
251
|
+
puts("#{string} (#{default})")
|
187
252
|
else
|
188
|
-
puts("#{string}
|
253
|
+
puts("#{string}")
|
189
254
|
end
|
190
255
|
end
|
191
256
|
end
|
data/lib/da_funk/i18n.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
class I18n
|
2
|
+
include DaFunk::Helper
|
3
|
+
class << self
|
4
|
+
attr_accessor :locale, :hash, :block_parse, :klasses
|
5
|
+
end
|
6
|
+
|
7
|
+
self.block_parse = Proc.new do |hash_,values_|
|
8
|
+
if values_[1].is_a?(Hash)
|
9
|
+
hash_[values_[0]] = values_[1].inject({}, &block_parse)
|
10
|
+
else
|
11
|
+
hash_[values_[0].to_sym] = values_[1]
|
12
|
+
end
|
13
|
+
hash_
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.filepath(klass)
|
17
|
+
"./#{klass}/i18n.json"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configure(klass, locale)
|
21
|
+
raise I18nError.new("File not found") if (! File.exists?(filepath(klass)))
|
22
|
+
self.parse(klass)
|
23
|
+
@locale = locale
|
24
|
+
raise I18nError.new("Locale not found") unless language
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.parse(klass)
|
28
|
+
@klasses ||= []
|
29
|
+
if @hash
|
30
|
+
self.merge(JSON.parse(File.read(filepath(klass))).inject({}, &block_parse))
|
31
|
+
else
|
32
|
+
@hash = JSON.parse(File.read(filepath(klass))).inject({}, &block_parse)
|
33
|
+
end
|
34
|
+
@klasses << klass
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.merge(hash2)
|
38
|
+
@hash ||= {}
|
39
|
+
hash2.keys.each do |key|
|
40
|
+
@hash[key] ||= {}
|
41
|
+
@hash[key].merge!(hash2[key] || {})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.language
|
46
|
+
@hash[@locale]
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.t(symbol, options = {})
|
50
|
+
if ! options[:time].nil?
|
51
|
+
parse_time(get(symbol), options[:time])
|
52
|
+
elsif options[:args]
|
53
|
+
get(symbol) % options[:args]
|
54
|
+
else
|
55
|
+
get(symbol)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.get(symbol)
|
60
|
+
language[symbol] || "No Translation"
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.pt(symbol, options = {})
|
64
|
+
puts(t(symbol, options))
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.parse_time(value, time)
|
68
|
+
value.sub("yy", time.year.to_s).
|
69
|
+
sub("y", time.year.to_s[2..3]).
|
70
|
+
sub("M", rjust(time.month.to_s, 2, "0")).
|
71
|
+
sub("d", rjust(time.day.to_s, 2, "0")).
|
72
|
+
sub("h", rjust(time.hour.to_s, 2, "0")).
|
73
|
+
sub("m", rjust(time.min.to_s, 2, "0")).
|
74
|
+
sub("s", rjust(time.sec.to_s, 2, "0"))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
data/lib/da_funk/iso8583.rb
CHANGED
data/lib/da_funk/rake_task.rb
CHANGED
@@ -10,7 +10,8 @@ module DaFunk
|
|
10
10
|
include ::Rake::DSL if defined?(::Rake::DSL)
|
11
11
|
|
12
12
|
attr_accessor :name, :libs, :tests, :tests_unit, :tests_integration, :root_path, :main_out,
|
13
|
-
:test_out, :resources, :mrbc, :mruby, :out_path, :resources_out, :debug
|
13
|
+
:test_out, :resources, :mrbc, :mruby, :out_path, :resources_out, :debug,
|
14
|
+
:tests_resources, :tests_res_out
|
14
15
|
|
15
16
|
def initialize
|
16
17
|
yield self if block_given?
|
@@ -20,6 +21,7 @@ module DaFunk
|
|
20
21
|
@tests ||= FileList['test/**/*test.rb']
|
21
22
|
@tests_integration ||= FileList['test/integration/**/*test.rb']
|
22
23
|
@tests_unit ||= FileList['test/unit/**/*test.rb']
|
24
|
+
@tests_resources ||= FileList['test/resources/**/*']
|
23
25
|
@root_path ||= "./"
|
24
26
|
@name ||= File.basename(File.expand_path(@root_path))
|
25
27
|
@out_path ||= File.join(root_path, "out", @name)
|
@@ -27,6 +29,7 @@ module DaFunk
|
|
27
29
|
@test_out ||= File.join(out_path, "test.mrb")
|
28
30
|
@resources ||= FileList['resources/**/*']
|
29
31
|
@resources_out ||= @resources.pathmap("%{resources,#{out_path}}p")
|
32
|
+
@tests_res_out ||= @tests_resources.pathmap("%{test/resources,out}p")
|
30
33
|
@mruby ||= "cloudwalk run"
|
31
34
|
@mrbc = get_mrbc_bin(@mrbc)
|
32
35
|
|
@@ -117,6 +120,9 @@ module DaFunk
|
|
117
120
|
namespace :test do
|
118
121
|
task :setup => :resources do
|
119
122
|
ENV["RUBY_PLATFORM"] = "mruby"
|
123
|
+
tests_resources.each_with_index do |file,dest_i|
|
124
|
+
FileUtils.cp(file, tests_res_out[dest_i]) if File.file?(file)
|
125
|
+
end
|
120
126
|
end
|
121
127
|
|
122
128
|
desc "Run unit test on mruby"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module DaFunk
|
2
|
+
class ScreenFlow
|
3
|
+
attr_accessor :list
|
4
|
+
|
5
|
+
def self.add(method, &block)
|
6
|
+
define_method method do
|
7
|
+
@list << CallbackFlow.new(self, @list.last, &block)
|
8
|
+
self
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
self.list = []
|
14
|
+
order
|
15
|
+
end
|
16
|
+
|
17
|
+
def order
|
18
|
+
end
|
19
|
+
|
20
|
+
def start
|
21
|
+
first = self.list.first
|
22
|
+
first.dispatch(true) if first
|
23
|
+
end
|
24
|
+
|
25
|
+
def confirm(text)
|
26
|
+
puts text.chomp
|
27
|
+
getc(0)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/device.rb
CHANGED
data/lib/device/application.rb
CHANGED
@@ -1,40 +1,98 @@
|
|
1
|
+
# Scenario
|
2
|
+
# 1. Load from scratch
|
3
|
+
# - No file downloaded
|
4
|
+
# - with file downloaded
|
5
|
+
# 2. Second load
|
6
|
+
# - No crc update
|
7
|
+
# - With crc update
|
8
|
+
|
1
9
|
class Device
|
2
10
|
class Application
|
3
|
-
|
11
|
+
attr_accessor :crc
|
12
|
+
attr_reader :label, :file, :type, :order, :name, :remote, :original, :crc_local
|
13
|
+
|
14
|
+
def self.delete(collection)
|
15
|
+
collection.each do |app|
|
16
|
+
begin
|
17
|
+
app.delete
|
18
|
+
rescue RuntimeError
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
4
22
|
|
5
|
-
def initialize(label,
|
6
|
-
@
|
23
|
+
def initialize(label, remote, type, crc)
|
24
|
+
@type = type
|
25
|
+
@crc = crc
|
26
|
+
@original = remote
|
7
27
|
@order, @label = split_label(label)
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
28
|
+
@remote = remote.sub("#{Device::Setting.company_name}_", "")
|
29
|
+
@name = remote.sub("#{Device::Setting.company_name}_", "").split(".")[0]
|
30
|
+
@file = check_path(@remote)
|
31
|
+
@crc_local = @crc if File.exists?(@file)
|
11
32
|
end
|
12
33
|
|
13
|
-
def
|
14
|
-
|
34
|
+
def download(force = false)
|
35
|
+
if force || outdated?
|
36
|
+
ret = Device::Transaction::Download.request_file(remote, file, crc_local)
|
37
|
+
else
|
38
|
+
ret = Device::Transaction::Download::FILE_NOT_CHANGE
|
39
|
+
end
|
40
|
+
@crc_local = @crc if ret == Device::Transaction::Download::SUCCESS
|
41
|
+
ret
|
15
42
|
end
|
16
43
|
|
17
|
-
def
|
18
|
-
@
|
44
|
+
def dir
|
45
|
+
@name
|
19
46
|
end
|
20
47
|
|
21
|
-
def
|
22
|
-
|
48
|
+
def exists?
|
49
|
+
File.exists? file
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete
|
53
|
+
File.delete(self.file) if exists?
|
54
|
+
if self.ruby? && Dir.exist?(self.dir) && self.dir != "main"
|
55
|
+
Dir.delete(self.dir)
|
56
|
+
end
|
23
57
|
end
|
24
58
|
|
25
59
|
def outdated?
|
26
|
-
return
|
27
|
-
|
28
|
-
|
60
|
+
return true unless File.exists?(file)
|
61
|
+
unless @crc_local
|
62
|
+
handle = File.open(file)
|
63
|
+
@crc_local = Device::Crypto.crc16_hex(handle.read)
|
64
|
+
end
|
65
|
+
@crc_local != @crc
|
29
66
|
ensure
|
30
|
-
|
67
|
+
handle.close if handle
|
31
68
|
end
|
32
69
|
|
33
70
|
def execute(json = "")
|
34
|
-
|
71
|
+
if posxml?
|
72
|
+
Device::Runtime.execute(remote, json)
|
73
|
+
else
|
74
|
+
Device::Runtime.execute(name, json)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def posxml?
|
79
|
+
@type == "posxml" || remote.include?(".posxml")
|
80
|
+
end
|
81
|
+
|
82
|
+
def ruby?
|
83
|
+
@type == "ruby" || (! remote.include? ".posxml")
|
35
84
|
end
|
36
85
|
|
37
86
|
private
|
87
|
+
|
88
|
+
def check_path(path)
|
89
|
+
if posxml?
|
90
|
+
"./shared/#{path}"
|
91
|
+
else
|
92
|
+
"#{path.gsub("#{Device::Setting.company_name}_", "")}.zip"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
38
96
|
def split_label(text)
|
39
97
|
if text == "X"
|
40
98
|
number, text = 0, "X"
|