butler-mainframe 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +45 -8
- data/lib/butler-mainframe.rb +20 -42
- data/lib/config/config.rb +3 -3
- data/lib/config/config_EXAMPLE_passport.rb +1 -0
- data/lib/config/config_EXAMPLE_pcomm.rb +1 -0
- data/lib/config/config_EXAMPLE_x3270.rb +1 -0
- data/lib/core/configuration.rb +2 -1
- data/lib/generators/butler/install_generator.rb +9 -2
- data/lib/generators/butler/templates/custom_functions.rb +85 -62
- data/lib/generators/rails/butler_mainframe_test/USAGE +8 -0
- data/lib/generators/rails/butler_mainframe_test/butler_mainframe_test_generator.rb +5 -0
- data/lib/generators/test_unit/butler_mainframe_test/USAGE +8 -0
- data/lib/generators/test_unit/butler_mainframe_test/butler_mainframe_test_generator.rb +46 -0
- data/lib/mainframe/customization/active_record.rb +1 -1
- data/lib/mainframe/customization/generic_functions.rb +17 -17
- data/lib/mainframe/emulators/passport.rb +9 -10
- data/lib/mainframe/emulators/pcomm.rb +10 -11
- data/lib/mainframe/emulators/x3270.rb +2 -1
- data/lib/mainframe/host_base.rb +8 -0
- data/test/test.rake +10 -6
- metadata +6 -3
- data/lib/config/settings_EXAMPLE.yml +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5dd2c3f32dca8f7e61d0ed59e11d59a158f7ff21
|
4
|
+
data.tar.gz: bc1a34ae83ca18147105f6ada19bf936cc36a417
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9dad70f5096a1bc38d53d8e5e9e3176e09ca29452d741e1c1f25158e3e471212227f4276d0d1016ab8f7e836476dadcd9d8b0528a986f05481debbf4b539067
|
7
|
+
data.tar.gz: dfeabba225bcbe7d395ce8cc0c7bf53f4a998c1cea8b4686489362a4b228f0e5ee796114d8850db079ceb8a2b53cc07edb94b268f8efe8a0ec5389614f893e32
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.6.0 [☰](https://github.com/marcomd/butler-mainframe/compare/v0.5.0...v0.6.0) October 29th, 2015
|
2
|
+
------------------------------
|
3
|
+
* Improved rails integration
|
4
|
+
* Added rails model test with the scaffold generator, see documentation
|
5
|
+
* Added env parameter in the configuration file
|
6
|
+
* Several little improvements
|
7
|
+
|
1
8
|
0.5.0 [☰](https://github.com/marcomd/butler-mainframe/compare/v0.4.0...v0.5.0) October 26th, 2015
|
2
9
|
------------------------------
|
3
10
|
* Moved sensible parameters in a separate yml file (private.yml) do not share it
|
data/README.md
CHANGED
@@ -160,7 +160,7 @@ My advice is to use navigate method for generic navigation and use a specific mo
|
|
160
160
|
|
161
161
|
## With Rails
|
162
162
|
|
163
|
-
This
|
163
|
+
This gem can be use on rails project.
|
164
164
|
Add in your gemfile
|
165
165
|
|
166
166
|
gem 'butler-mainframe'
|
@@ -169,11 +169,11 @@ then
|
|
169
169
|
|
170
170
|
bundle install
|
171
171
|
|
172
|
-
run generator to copy configuration files
|
172
|
+
run generator to copy configuration files passing your emulator as parameter (default x3270)
|
173
173
|
|
174
|
-
rails g butler:install --emulator=
|
174
|
+
rails g butler:install --emulator=pcomm
|
175
175
|
|
176
|
-
|
176
|
+
My advice is to have a model for every function.
|
177
177
|
In this simple example i have to insert an invoice number on a cics map so i create the invoice model:
|
178
178
|
|
179
179
|
rails generate scaffold invoice number:integer
|
@@ -222,12 +222,49 @@ Class Invoice
|
|
222
222
|
end
|
223
223
|
```
|
224
224
|
|
225
|
-
|
226
|
-
The uses are many and only limited by your imagination!
|
227
|
-
Experiment and you'll find the solution right for you :rocket:
|
225
|
+
If massive uses or one shot depends on your needs and according to these must be optimized the function.
|
228
226
|
|
227
|
+
The uses are many and only limited by your imagination! :rocket:
|
229
228
|
|
230
|
-
|
229
|
+
Experiment and you'll find the solution right for you
|
230
|
+
|
231
|
+
## Test
|
232
|
+
|
233
|
+
### Test models with rails
|
234
|
+
|
235
|
+
Add the butler test helper in yours rails config/application.rb before create the resource.
|
236
|
+
In this way will be added for you the test cases for that model.
|
237
|
+
Available only for the test unit framework.
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
config.generators do |g|
|
241
|
+
...
|
242
|
+
g.test_framework :test_unit
|
243
|
+
g.helper :butler_mainframe_test
|
244
|
+
end
|
245
|
+
```
|
246
|
+
|
247
|
+
For example if you created the invoice resource:
|
248
|
+
|
249
|
+
With rails 4:
|
250
|
+
|
251
|
+
rake test test\models\butler_mainframe_invoice_test.rb
|
252
|
+
|
253
|
+
Rails 3 is not tested yet:
|
254
|
+
|
255
|
+
ruby -I test unit butler_mainframe_invoice_test.rb
|
256
|
+
|
257
|
+
You should get something like this:
|
258
|
+
|
259
|
+
** Connection established with PComm A **
|
260
|
+
...
|
261
|
+
Session closed because started by this process with id 1234
|
262
|
+
|
263
|
+
Finished in 13.044988s, 0.1533 runs/s, 0.3066 assertions/s.
|
264
|
+
|
265
|
+
2 runs, 4 assertions, 0 failures, 0 errors, 0 skips
|
266
|
+
|
267
|
+
### Test with rake
|
231
268
|
|
232
269
|
Simple embedded tests
|
233
270
|
|
data/lib/butler-mainframe.rb
CHANGED
@@ -8,7 +8,6 @@
|
|
8
8
|
|
9
9
|
require 'core/configuration'
|
10
10
|
require 'core/configuration_dynamic'
|
11
|
-
require 'config/config'
|
12
11
|
|
13
12
|
module ButlerMainframe
|
14
13
|
def self.root
|
@@ -16,49 +15,28 @@ module ButlerMainframe
|
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
19
|
-
#
|
20
|
-
|
21
|
-
# I18n.load_path=Dir['config/locales/*.yml']
|
22
|
-
# I18n.locale = ButlerMainframe.configuration.language
|
18
|
+
# This project use monkey patch for 1.8 compatibility
|
19
|
+
require 'mainframe/host_base'
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
debug = env == "development" ? true : false
|
21
|
+
# puts "Butler Mainframe #{defined?(Rails) ? 'with' : 'without'} Rails" #DEBUG
|
22
|
+
if defined?(Rails)
|
23
|
+
# Rails use own configuration file into initializers folder
|
28
24
|
|
29
|
-
#
|
30
|
-
require
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
require 'mainframe/customization/active_record'
|
39
|
-
# puts "Extending Host class with #{Host3270::ActiveRecord}" if debug
|
40
|
-
# Use monkey patch for 1.8 compatibility
|
41
|
-
class ButlerMainframe::Host
|
42
|
-
include Host3270::ActiveRecord
|
43
|
-
end
|
25
|
+
# This module adds additional methods useful only for projects rails
|
26
|
+
require 'mainframe/customization/active_record'
|
27
|
+
class ButlerMainframe::HostBase
|
28
|
+
include ButlerMainframe::ActiveRecord
|
29
|
+
end
|
30
|
+
else
|
31
|
+
# ...if it is not a rails project load configuration file
|
32
|
+
require 'config/config'
|
44
33
|
|
45
|
-
require
|
46
|
-
|
47
|
-
|
48
|
-
include Host3270::GenericFunctions
|
49
|
-
end
|
34
|
+
# require the emulator sub class specified in the config.rb
|
35
|
+
raise "Define your host gateway in the configuration file!" unless ButlerMainframe.configuration.host_gateway
|
36
|
+
require "mainframe/emulators/#{ButlerMainframe.configuration.host_gateway.to_s.downcase}"
|
50
37
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
include Host3270::CustomFunctions
|
38
|
+
%w(settings.yml private.yml).each do |file|
|
39
|
+
filepath = File.join(ButlerMainframe.root,'lib','config',file)
|
40
|
+
ButlerMainframe::Settings.load!(filepath, :env => ButlerMainframe.configuration.env) if File.exist? filepath
|
55
41
|
end
|
56
|
-
end
|
57
|
-
|
58
|
-
=begin
|
59
|
-
# To test in irb
|
60
|
-
require 'butler-mainframe'
|
61
|
-
host=ButlerMainframe::Host.new(debug: :full)
|
62
|
-
host.scan_page
|
63
|
-
host.navigate :next
|
64
|
-
=end
|
42
|
+
end
|
data/lib/config/config.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
ButlerMainframe.configure do |config|
|
2
|
-
config.host_gateway = :x3270
|
3
|
-
config.session_path = '"C:/Program Files (x86)/wc3270/ws3270.exe" YOUR_HOST_IP -model 2 --'
|
4
|
-
config.timeout = 6 # In seconds
|
2
|
+
# config.host_gateway = :x3270
|
3
|
+
# config.session_path = '"C:/Program Files (x86)/wc3270/ws3270.exe" YOUR_HOST_IP -model 2 --'
|
4
|
+
# config.timeout = 6 # In seconds
|
5
5
|
end
|
6
6
|
|
@@ -7,5 +7,6 @@ ButlerMainframe.configure do |config|
|
|
7
7
|
config.session_path = '"C:/Program Files (x86)/IBM/Personal Communications/pcsws.exe" "C:/Users/YOUR_USER/AppData/Roaming/IBM/Personal Communications/host3270.ws" /Q /H /S=A'
|
8
8
|
config.session_tag = 'A'
|
9
9
|
config.timeout = 6000
|
10
|
+
#config.env = 'production'
|
10
11
|
end
|
11
12
|
|
data/lib/core/configuration.rb
CHANGED
@@ -2,7 +2,7 @@ module ButlerMainframe
|
|
2
2
|
class Configuration
|
3
3
|
attr_writer :allow_sign_up
|
4
4
|
|
5
|
-
attr_accessor :language, :host_gateway, :browser_path, :session_url, :session_path, :session_tag, :timeout
|
5
|
+
attr_accessor :language, :host_gateway, :browser_path, :session_url, :session_path, :session_tag, :timeout, :env
|
6
6
|
|
7
7
|
def initialize
|
8
8
|
@language = :en
|
@@ -12,6 +12,7 @@ module ButlerMainframe
|
|
12
12
|
@session_path = ""
|
13
13
|
@session_tag = nil
|
14
14
|
@timeout = 1000
|
15
|
+
@env = 'development'
|
15
16
|
end
|
16
17
|
|
17
18
|
end
|
@@ -12,12 +12,19 @@ module Butler
|
|
12
12
|
|
13
13
|
def copy_to_local
|
14
14
|
copy_file "butler/templates/custom_functions.rb", "config/initializers/butler_custom_functions.rb"
|
15
|
-
copy_file "../config/settings.yml",
|
15
|
+
copy_file "../config/settings.yml", "config/butler.yml"
|
16
|
+
copy_file "../config/private.yml", "config/butler_private.yml"
|
16
17
|
file = "config/initializers/butler.rb"
|
17
18
|
copy_file "../config/config_EXAMPLE_#{options[:emulator]}.rb", file
|
18
19
|
append_file file do
|
19
20
|
<<-FILE.gsub(/^ /, '')
|
20
|
-
|
21
|
+
raise "Define your host gateway in the rails initializer file!" unless ButlerMainframe.configuration.host_gateway
|
22
|
+
require "mainframe/emulators/#{ButlerMainframe.configuration.host_gateway.to_s.downcase}"
|
23
|
+
|
24
|
+
%w(butler.yml butler_private.yml).each do |file|
|
25
|
+
filepath = File.join(Rails.root,'config',file)
|
26
|
+
ButlerMainframe::Settings.load!(filepath, :env => Rails.env) if File.exist? filepath
|
27
|
+
end
|
21
28
|
FILE
|
22
29
|
end
|
23
30
|
end
|
@@ -1,27 +1,16 @@
|
|
1
1
|
# These modules contain extensions for the Host class
|
2
|
-
module
|
2
|
+
module ButlerMainframe
|
3
3
|
module CustomFunctions
|
4
4
|
### Insert here your custom methods ###
|
5
5
|
|
6
6
|
### Update default generic function ###
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# def go_back; exec_command "PA2" end
|
10
|
-
#
|
11
|
-
# def do_confirm; exec_command "PF3" end
|
12
|
-
#
|
13
|
-
# def do_quit; exec_command "CLEAR" end
|
14
|
-
#
|
15
|
-
# def do_erase; exec_command "ERASE EOF" end
|
16
|
-
#
|
17
|
-
# # If you add your static screen you must add it in the navigation method to define how to manage it
|
7
|
+
# If you add your static screen you must add it in the navigation method to define how to manage it
|
18
8
|
# def destination_list
|
19
|
-
# [
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# :back]
|
9
|
+
# [:company_menu,
|
10
|
+
# :cics_selection,
|
11
|
+
# :session_login,
|
12
|
+
# :next,
|
13
|
+
# :back]
|
25
14
|
# end
|
26
15
|
#
|
27
16
|
# # Use navigation method to move through the static screens
|
@@ -32,91 +21,98 @@ module Host3270
|
|
32
21
|
# # :raise_on_abend => false raise an exception if an abend is occured
|
33
22
|
# def navigate destination, options={}
|
34
23
|
# options = {
|
24
|
+
# :session_user => ButlerMainframe::Settings.session_user,
|
25
|
+
# :session_password => ButlerMainframe::Settings.session_password,
|
35
26
|
# :cics => ButlerMainframe::Settings.cics,
|
36
|
-
# :
|
37
|
-
# :password => ButlerMainframe::Settings.password,
|
27
|
+
# :company_menu => ButlerMainframe::Settings.company_menu,
|
38
28
|
# :raise_on_abend => false
|
39
29
|
# }.merge(options)
|
40
|
-
#
|
30
|
+
# max_attempts_number = ButlerMainframe::Settings.max_attempts_number
|
41
31
|
# transactions_cics = ButlerMainframe::Settings.transactions_cics
|
42
32
|
#
|
43
33
|
# raise "Destination #{destination} not valid, please use: #{destination_list.join(', ')}" unless destination_list.include? destination
|
44
|
-
#
|
45
|
-
#
|
34
|
+
#
|
35
|
+
# puts "Navigating to #{destination}" if @debug
|
36
|
+
# destination_found = nil
|
37
|
+
# attempt_number = 0
|
38
|
+
# while !destination_found do
|
39
|
+
# attempt_number += 1
|
40
|
+
#
|
46
41
|
# if abend?
|
42
|
+
# puts "Navigate: abend" if @debug
|
47
43
|
# options[:raise_on_abend] ? raise(catch_abend) : do_quit
|
48
44
|
# elsif company_menu?
|
45
|
+
# puts "Navigating to #{destination} from company menu" if @debug
|
49
46
|
# case destination
|
50
47
|
# when :cics_selection,
|
51
48
|
# :session_login then
|
52
49
|
# do_quit
|
53
50
|
# when :back then
|
54
51
|
# do_quit
|
55
|
-
#
|
52
|
+
# destination_found = true
|
56
53
|
# when :next then
|
57
|
-
# company_menu
|
58
|
-
#
|
59
|
-
# when :company_menu then
|
54
|
+
# company_menu options[:company_menu]
|
55
|
+
# destination_found = true
|
56
|
+
# when :company_menu then destination_found = true
|
60
57
|
# else
|
61
58
|
# # Every other destination is forward
|
62
|
-
# company_menu
|
59
|
+
# company_menu options[:company_menu]
|
63
60
|
# end
|
64
61
|
# elsif cics?
|
62
|
+
# puts "Navigating to #{destination} from cics" if @debug
|
65
63
|
# case destination
|
66
64
|
# when :cics_selection,
|
67
65
|
# :session_login then
|
68
|
-
#
|
69
|
-
# do_enter
|
66
|
+
# execute_cics ButlerMainframe::Settings.logoff_cics
|
70
67
|
# when :back then
|
71
|
-
#
|
72
|
-
#
|
73
|
-
# bol_found = true; break
|
68
|
+
# execute_cics ButlerMainframe::Settings.logoff_cics
|
69
|
+
# destination_found = true
|
74
70
|
# when :next then
|
75
|
-
#
|
76
|
-
#
|
77
|
-
# bol_found = true; break
|
71
|
+
# execute_cics transactions_cics[:main_application]
|
72
|
+
# destination_found = true
|
78
73
|
# when :company_menu then
|
79
|
-
#
|
80
|
-
# do_enter
|
74
|
+
# execute_cics transactions_cics[:company_menu]
|
81
75
|
# else
|
82
76
|
# #If we are in CICS with blank screen start the first transaction
|
83
|
-
#
|
84
|
-
# do_enter
|
77
|
+
# execute_cics transactions_cics[:main_application]
|
85
78
|
# end
|
86
79
|
# elsif cics_selection?
|
80
|
+
# puts "Navigating to #{destination} from cics selection" if @debug
|
87
81
|
# case destination
|
88
|
-
# when :cics_selection then
|
82
|
+
# when :cics_selection then destination_found = true
|
89
83
|
# when :session_login then exec_command("PF3")
|
90
84
|
# when :next then
|
91
85
|
# cics_selection options[:cics] if options[:cics]
|
92
|
-
#
|
86
|
+
# destination_found = true
|
93
87
|
# when :back then
|
94
88
|
# exec_command("PF3")
|
95
|
-
#
|
89
|
+
# destination_found = true
|
96
90
|
# else
|
97
91
|
# cics_selection options[:cics] if options[:cics]
|
98
92
|
# end
|
99
93
|
# elsif session_login?
|
94
|
+
# puts "Navigating to #{destination} from session login" if @debug
|
100
95
|
# case destination
|
101
96
|
# when :session_login,
|
102
|
-
# :back then
|
97
|
+
# :back then destination_found = true
|
103
98
|
# when :next then
|
104
|
-
# session_login options[:
|
105
|
-
#
|
99
|
+
# session_login options[:session_user], options[:session_password]
|
100
|
+
# destination_found = true
|
106
101
|
# else
|
107
|
-
# session_login options[:
|
102
|
+
# session_login options[:session_user], options[:session_password]
|
108
103
|
# end
|
109
104
|
# else
|
105
|
+
# puts "Navigating to #{destination} from unknown screen" if @debug
|
110
106
|
# # If we do not know where we are...
|
111
107
|
# case destination
|
112
|
-
# when :session_login
|
108
|
+
# when :session_login then
|
113
109
|
# # ...to come back to the first screen we surely have to go back
|
114
110
|
# go_back
|
115
111
|
# when :back then
|
116
112
|
# # ...we can try to go back (not all the screen may go back in the same way)
|
117
113
|
# go_back
|
118
|
-
#
|
119
|
-
# when :next
|
114
|
+
# destination_found = true
|
115
|
+
# when :next then
|
120
116
|
# # ...but we dont know how to move forward
|
121
117
|
# raise "Define how to go forward in the navigation method on generic function module"
|
122
118
|
# else
|
@@ -124,10 +120,11 @@ module Host3270
|
|
124
120
|
# raise "Destination #{destination} not defined in the current screen"
|
125
121
|
# end
|
126
122
|
# end
|
123
|
+
# break if attempt_number > max_attempts_number
|
127
124
|
# wait_session
|
128
125
|
# end
|
129
126
|
#
|
130
|
-
# raise "It was waiting #{destination} map instead of: #{screen_title(:rows => 2).strip}" unless
|
127
|
+
# raise "It was waiting #{destination} map instead of: #{screen_title(:rows => 2).strip}" unless destination_found
|
131
128
|
# end
|
132
129
|
#
|
133
130
|
# # Check if we are the first blank cics screen
|
@@ -141,15 +138,20 @@ module Host3270
|
|
141
138
|
# end
|
142
139
|
#
|
143
140
|
# # Login to mainframe
|
144
|
-
# # param1 user
|
145
|
-
# # param2 password
|
146
|
-
# def session_login
|
141
|
+
# # param1 user(array) [text, y, x]
|
142
|
+
# # param2 password(array) [text, y, x]
|
143
|
+
# def session_login ar_user, ar_password
|
147
144
|
# puts "Starting session login..." if @debug
|
145
|
+
# user, y_user, x_user = ar_user
|
146
|
+
# raise "Check session user configuration! #{user} #{y_user} #{x_user}" unless user && y_user && x_user
|
147
|
+
# password, y_password, x_password = ar_password
|
148
|
+
# raise "Check session password configuration! #{password} #{y_password} #{x_password}" unless password && y_password && x_password
|
149
|
+
#
|
148
150
|
# wait_session
|
149
151
|
# #inizializza_sessione
|
150
152
|
# raise "It was waiting session login map instead of: #{screen_title}" unless session_login?
|
151
|
-
# write user, :y =>
|
152
|
-
# write password, :y =>
|
153
|
+
# write user, :y => y_user, :x => x_user
|
154
|
+
# write password, :y => y_password, :x => x_password, :sensible_data => true
|
153
155
|
# do_enter
|
154
156
|
# end
|
155
157
|
#
|
@@ -159,12 +161,15 @@ module Host3270
|
|
159
161
|
# end
|
160
162
|
#
|
161
163
|
# # On this map, we have to select the cics environment
|
162
|
-
# # param1 cics
|
163
|
-
# def cics_selection
|
164
|
+
# # param1 cics(array) [text, y, x]
|
165
|
+
# def cics_selection ar_cics
|
164
166
|
# puts "Starting selezione_cics..." if @debug
|
167
|
+
# cics, y_cics, x_cics = ar_cics
|
168
|
+
# raise "Check cics configuration! #{cics} #{y_cics} #{x_cics}" unless cics && y_cics && x_cics
|
169
|
+
#
|
165
170
|
# wait_session
|
166
171
|
# raise "It was waiting cics selezion map instead of: #{screen_title}, message: #{catch_message}" unless cics_selection?
|
167
|
-
# write cics, :y =>
|
172
|
+
# write cics, :y => y_cics, :x => x_cics
|
168
173
|
# do_enter
|
169
174
|
# wait_session 1
|
170
175
|
# end
|
@@ -176,11 +181,14 @@ module Host3270
|
|
176
181
|
#
|
177
182
|
# # On this map, we have to select the cics environment
|
178
183
|
# # param1 cics usually is a number
|
179
|
-
# def company_menu
|
184
|
+
# def company_menu ar_menu
|
180
185
|
# puts "Starting company menu..." if @debug
|
186
|
+
# menu, y_menu, x_menu = ar_menu
|
187
|
+
# raise "Check company menu configuration! #{menu} #{y_menu} #{x_menu}" unless menu && y_menu && x_menu
|
188
|
+
#
|
181
189
|
# wait_session
|
182
190
|
# raise "It was waiting company menu map instead of: #{screen_title}, message: #{catch_message}" unless company_menu?
|
183
|
-
# write
|
191
|
+
# write menu, :y => y_menu, :x => x_menu
|
184
192
|
# do_enter
|
185
193
|
# end
|
186
194
|
#
|
@@ -214,9 +222,24 @@ module Host3270
|
|
214
222
|
# }.merge(options)
|
215
223
|
# scan(:y1 => 1, :x1 => 1, :y2 => options[:rows], :x2 => 80)
|
216
224
|
# end
|
225
|
+
#
|
226
|
+
# def execute_cics name
|
227
|
+
# write name, :y => 1, :x => 2
|
228
|
+
# do_enter
|
229
|
+
# end
|
230
|
+
#
|
231
|
+
# def do_enter; exec_command "ENTER" end
|
232
|
+
#
|
233
|
+
# def go_back; exec_command "PA2" end
|
234
|
+
#
|
235
|
+
# def do_confirm; exec_command "PF3" end
|
236
|
+
#
|
237
|
+
# def do_quit; exec_command "CLEAR" end
|
238
|
+
#
|
239
|
+
# def do_erase; exec_command "ERASE EOF" end
|
217
240
|
end
|
218
241
|
end
|
219
242
|
|
220
243
|
class ButlerMainframe::Host
|
221
|
-
include
|
244
|
+
include ButlerMainframe::CustomFunctions
|
222
245
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rails/generators/test_unit'
|
2
|
+
require 'rails/generators/resource_helpers'
|
3
|
+
|
4
|
+
module TestUnit # :nodoc:
|
5
|
+
module Generators # :nodoc:
|
6
|
+
class ButlerMainframeTestGenerator < Base # :nodoc:
|
7
|
+
include Rails::Generators::ResourceHelpers
|
8
|
+
|
9
|
+
source_root File.expand_path('../templates', __FILE__)
|
10
|
+
|
11
|
+
def create_test_file
|
12
|
+
create_file "test/#{/^4\./ === Rails.version ? 'models' : 'unit'}/butler_mainframe_#{file_name}_test.rb",
|
13
|
+
<<-FILE.gsub(/^ /, '')
|
14
|
+
require 'test_helper'
|
15
|
+
|
16
|
+
class #{class_name}Test < ActiveSupport::TestCase
|
17
|
+
test "Basic navigation" do
|
18
|
+
params = {:debug => true, :wait_debug => 0.5}
|
19
|
+
host = ButlerMainframe::Host.new(params)
|
20
|
+
host.navigate :session_login
|
21
|
+
assert host.session_login?, 'navigate :session_login => this is not the session login'
|
22
|
+
|
23
|
+
host.navigate :next
|
24
|
+
assert !host.session_login?, 'navigate :next => does not pass login screen'
|
25
|
+
|
26
|
+
host.close_session
|
27
|
+
assert host.action[:object] == nil, "Close session failed!"
|
28
|
+
end
|
29
|
+
|
30
|
+
test "#{class_name} navigation" do
|
31
|
+
params = {:debug => true, :wait_debug => 0.5}
|
32
|
+
host = ButlerMainframe::Host.new(params)
|
33
|
+
|
34
|
+
#host.navigate :your_starting_screen
|
35
|
+
# WRITE YOUR TEST
|
36
|
+
|
37
|
+
host.close_session
|
38
|
+
assert host.action[:object] == nil, "Close session failed!"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
FILE
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,25 +1,14 @@
|
|
1
1
|
# These modules contain extensions for the Host class
|
2
|
-
module
|
2
|
+
module ButlerMainframe
|
3
3
|
module GenericFunctions
|
4
4
|
|
5
|
-
def do_enter; exec_command "ENTER" end
|
6
|
-
|
7
|
-
def go_back; exec_command "PA2" end
|
8
|
-
|
9
|
-
def do_confirm; exec_command "PF3" end
|
10
|
-
|
11
|
-
def do_quit; exec_command "CLEAR" end
|
12
|
-
|
13
|
-
def do_erase; exec_command "ERASE EOF" end
|
14
|
-
|
15
5
|
# If you add your static screen you must add it in the navigation method to define how to manage it
|
16
6
|
def destination_list
|
17
|
-
[
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
:back]
|
7
|
+
[:company_menu,
|
8
|
+
:cics_selection,
|
9
|
+
:session_login,
|
10
|
+
:next,
|
11
|
+
:back]
|
23
12
|
end
|
24
13
|
|
25
14
|
# Use navigation method to move through the static screens
|
@@ -236,6 +225,17 @@ module Host3270
|
|
236
225
|
write name, :y => 1, :x => 2
|
237
226
|
do_enter
|
238
227
|
end
|
228
|
+
|
229
|
+
def do_enter; exec_command "ENTER" end
|
230
|
+
|
231
|
+
def go_back; exec_command "PA2" end
|
232
|
+
|
233
|
+
def do_confirm; exec_command "PF3" end
|
234
|
+
|
235
|
+
def do_quit; exec_command "CLEAR" end
|
236
|
+
|
237
|
+
def do_erase; exec_command "ERASE EOF" end
|
238
|
+
|
239
239
|
end
|
240
240
|
|
241
241
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'win32ole'
|
2
|
-
require 'mainframe/host_base'
|
3
2
|
|
4
3
|
# This class use Rocket 3270 emulator API
|
5
4
|
# http://www.zephyrcorp.com/legacy-integration/Documentation/passport_host_integration_objects.htm
|
@@ -12,37 +11,37 @@ module ButlerMainframe
|
|
12
11
|
def sub_create_object options={}
|
13
12
|
str_obj = 'PASSPORT.System'
|
14
13
|
puts "#{Time.now.strftime "%H:%M:%S"} Creating object #{str_obj}..." if @debug == :full
|
15
|
-
@action[:
|
16
|
-
@screen = @action[:
|
14
|
+
@action[:object] = WIN32OLE.new(str_obj)
|
15
|
+
@screen = @action[:object].Sessions(@session_tag).Screen if sub_object_created?
|
17
16
|
end
|
18
17
|
|
19
18
|
# Check is session is started
|
20
19
|
def sub_object_created?
|
21
|
-
res = @action[:
|
20
|
+
res = @action[:object] && @action[:object].Sessions(@session_tag)
|
22
21
|
puts "#{Time.now.strftime "%H:%M:%S"} Terminal successfully detected" if @debug == :full && res
|
23
22
|
res
|
24
23
|
end
|
25
24
|
|
26
25
|
# Check is session is operative
|
27
26
|
def sub_object_ready?
|
28
|
-
res = @action[:
|
27
|
+
res = @action[:object].Sessions(@session_tag).Connected == -1
|
29
28
|
puts "#{Time.now.strftime "%H:%M:%S"} Session ready" if @debug == :full && res
|
30
29
|
res
|
31
30
|
end
|
32
31
|
|
33
32
|
def sub_name
|
34
|
-
"#{@action[:
|
33
|
+
"#{@action[:object].Name} #{@action[:object].Sessions(@session_tag).Name}"
|
35
34
|
end
|
36
35
|
|
37
36
|
def sub_fullname
|
38
|
-
"#{sub_name} #{@action[:
|
37
|
+
"#{sub_name} #{@action[:object].Sessions(@session_tag).FullName}"
|
39
38
|
end
|
40
39
|
|
41
40
|
#Ends the connection and closes the session
|
42
41
|
def sub_close_session
|
43
|
-
@action[:
|
44
|
-
@action[:
|
45
|
-
@action[:
|
42
|
+
@action[:object].Sessions(@session_tag).Close
|
43
|
+
@action[:object].Quit
|
44
|
+
@action[:object] = nil
|
46
45
|
end
|
47
46
|
|
48
47
|
#Execute keyboard command like PF1 or PA2 or ENTER ...
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'win32ole'
|
2
|
-
require 'mainframe/host_base'
|
3
2
|
|
4
3
|
# This class use IBM personal communication
|
5
4
|
# http://www-01.ibm.com/support/knowledgecenter/SSEQ5Y_6.0.0/welcome.html
|
@@ -14,38 +13,38 @@ module ButlerMainframe
|
|
14
13
|
def sub_create_object options={}
|
15
14
|
str_obj = 'PComm.autECLSession'
|
16
15
|
puts "#{Time.now.strftime "%H:%M:%S"} Creating object #{str_obj}..." if @debug == :full
|
17
|
-
@action[:
|
18
|
-
@action[:
|
19
|
-
@space = @action[:
|
20
|
-
@screen = @action[:
|
16
|
+
@action[:object] = WIN32OLE.new(str_obj)
|
17
|
+
@action[:object].SetConnectionByName @session_tag
|
18
|
+
@space = @action[:object].autECLPS
|
19
|
+
@screen = @action[:object].autECLOIA
|
21
20
|
end
|
22
21
|
|
23
22
|
# Check is session is started
|
24
23
|
def sub_object_created?
|
25
|
-
res = @action[:
|
24
|
+
res = @action[:object] && @action[:object].CommStarted
|
26
25
|
puts "#{Time.now.strftime "%H:%M:%S"} Terminal successfully detected" if @debug == :full && res
|
27
26
|
res
|
28
27
|
end
|
29
28
|
|
30
29
|
# Check is session is operative
|
31
30
|
def sub_object_ready?
|
32
|
-
res = @action[:
|
31
|
+
res = @action[:object].Ready
|
33
32
|
puts "#{Time.now.strftime "%H:%M:%S"} Session ready" if @debug == :full && res
|
34
33
|
res
|
35
34
|
end
|
36
35
|
|
37
36
|
def sub_name
|
38
|
-
"PComm #{@action[:
|
37
|
+
"PComm #{@action[:object].Name}"
|
39
38
|
end
|
40
39
|
|
41
40
|
def sub_fullname
|
42
|
-
"#{sub_name} #{@action[:
|
41
|
+
"#{sub_name} #{@action[:object].ConnType}"
|
43
42
|
end
|
44
43
|
|
45
44
|
#Ends the connection and closes the session
|
46
45
|
def sub_close_session
|
47
|
-
@action[:
|
48
|
-
@action[:
|
46
|
+
@action[:object].StopCommunication
|
47
|
+
@action[:object] = nil
|
49
48
|
# See http://www-01.ibm.com/support/knowledgecenter/SSEQ5Y_6.0.0/com.ibm.pcomm.doc/books/html/admin_guide10.htm?lang=en
|
50
49
|
Process.spawn "PCOMSTOP /S=#{@session_tag} /q" if @pid
|
51
50
|
# Process.kill 9, @pid #Another way is to kill the process but the session start 2nd process pcscm.exe
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'open3'
|
2
|
-
require 'mainframe/host_base'
|
3
2
|
|
4
3
|
# This class use X3270, an interesting project open source
|
5
4
|
# http://x3270.bgp.nu/Windows/wc3270-script.html
|
@@ -14,6 +13,7 @@ module ButlerMainframe
|
|
14
13
|
puts "#{Time.now.strftime "%H:%M:%S"} Creating object #{str_obj}..." if @debug == :full
|
15
14
|
@action = {}
|
16
15
|
@action[:in], @action[:out], @action[:thr] = Open3.popen2e(str_obj)
|
16
|
+
@action[:object] = true
|
17
17
|
sleep WAIT_AFTER_START_SESSION
|
18
18
|
@pid = @action[:thr].pid
|
19
19
|
end
|
@@ -44,6 +44,7 @@ module ButlerMainframe
|
|
44
44
|
def sub_close_session
|
45
45
|
@action[:in].close
|
46
46
|
@action[:out].close
|
47
|
+
@action[:object] = nil
|
47
48
|
end
|
48
49
|
|
49
50
|
#Execute keyboard command like PF1 or PA2 or ENTER ...
|
data/lib/mainframe/host_base.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
require 'mainframe/customization/generic_functions'
|
2
|
+
|
1
3
|
module ButlerMainframe
|
2
4
|
# This is the host class base that contains high level logic
|
3
5
|
# It uses sub method that have to be defined in the specific sub class
|
4
6
|
class HostBase
|
7
|
+
include ButlerMainframe::GenericFunctions
|
5
8
|
|
6
9
|
attr_reader :action, :wait
|
7
10
|
attr_accessor :debug
|
@@ -40,6 +43,10 @@ module ButlerMainframe
|
|
40
43
|
|
41
44
|
# Ends the connection and closes the session
|
42
45
|
def close_session
|
46
|
+
# puts "[DEPRECATED] .close_session will no longer be available, please use .quit"
|
47
|
+
quit
|
48
|
+
end
|
49
|
+
def quit
|
43
50
|
puts "Closing session with criterion \"#{@close_session}\"" if @debug
|
44
51
|
case @close_session
|
45
52
|
when :always
|
@@ -57,6 +64,7 @@ module ButlerMainframe
|
|
57
64
|
end
|
58
65
|
end
|
59
66
|
|
67
|
+
|
60
68
|
# Sleep time between operations
|
61
69
|
def wait_session wait=nil
|
62
70
|
sleep(wait || (@debug ? @wait_debug : @wait))
|
data/test/test.rake
CHANGED
@@ -43,27 +43,31 @@ def simple_iteration options={}
|
|
43
43
|
host = options[:host] || ButlerMainframe::Host.new(params)
|
44
44
|
|
45
45
|
navigate host, :session_login
|
46
|
-
|
47
46
|
str_screen1 = host.scan_page
|
48
47
|
raise 'host.scan_page' if str_screen1.empty?
|
48
|
+
raise 'navigate :session_login => this is not the session login' unless host.session_login?
|
49
49
|
|
50
50
|
navigate host, :next
|
51
51
|
str_screen2 = host.scan_page
|
52
|
-
raise 'navigate :next
|
52
|
+
raise 'navigate :next from :session_login => the screen is not changed' if str_screen1 == str_screen2
|
53
|
+
|
54
|
+
raise 'navigate :next => does not pass login screen' if host.session_login?
|
53
55
|
|
54
56
|
navigate host, :next
|
55
|
-
|
56
|
-
raise 'navigate :next does not pass cics selection' if str_screen1 == str_screen2
|
57
|
+
raise 'navigate :next => does not pass cics selection' if host.cics_selection?
|
57
58
|
|
58
59
|
# Go back until the first screen
|
59
60
|
navigate host, :session_login
|
61
|
+
raise 'navigate :session_login => this is not the session login' unless host.session_login?
|
60
62
|
|
61
|
-
raise "host.scan row failed" unless host.scan(:y
|
62
|
-
raise "host.scan area failed" unless host.scan(:y1 => 1, :x1 => 1, :y2
|
63
|
+
raise "host.scan row failed" unless host.scan(:y => 1, :x => 1, :len => ButlerMainframe::Host::MAX_TERMINAL_COLUMNS).size == ButlerMainframe::Host::MAX_TERMINAL_COLUMNS
|
64
|
+
raise "host.scan area failed" unless host.scan(:y1 => 1, :x1 => 1, :y2 => 3, :x2 => ButlerMainframe::Host::MAX_TERMINAL_COLUMNS).size == (ButlerMainframe::Host::MAX_TERMINAL_COLUMNS * 3)
|
63
65
|
|
64
66
|
navigate host, :back
|
67
|
+
raise 'navigate :back from :session_login => this is not the session login' unless host.session_login?
|
65
68
|
|
66
69
|
navigate host, :company_menu
|
70
|
+
raise 'navigate :company_menu from :session_login => this is not the company menu' unless host.company_menu?
|
67
71
|
|
68
72
|
navigate host, :next
|
69
73
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: butler-mainframe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marco Mastrodonato
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: This gem provides a virtual butler which can perform your custom tasks
|
14
14
|
on a 3270 emulator. Choose your emulator, configure your task and discover a new
|
@@ -30,13 +30,16 @@ files:
|
|
30
30
|
- lib/config/config_EXAMPLE_x3270.rb
|
31
31
|
- lib/config/private.yml
|
32
32
|
- lib/config/settings.yml
|
33
|
-
- lib/config/settings_EXAMPLE.yml
|
34
33
|
- lib/core/configuration.rb
|
35
34
|
- lib/core/configuration_dynamic.rb
|
36
35
|
- lib/generators/butler/USAGE
|
37
36
|
- lib/generators/butler/install_generator.rb
|
38
37
|
- lib/generators/butler/templates/custom_functions.rb
|
39
38
|
- lib/generators/butler_mainframe.rb
|
39
|
+
- lib/generators/rails/butler_mainframe_test/USAGE
|
40
|
+
- lib/generators/rails/butler_mainframe_test/butler_mainframe_test_generator.rb
|
41
|
+
- lib/generators/test_unit/butler_mainframe_test/USAGE
|
42
|
+
- lib/generators/test_unit/butler_mainframe_test/butler_mainframe_test_generator.rb
|
40
43
|
- lib/mainframe/customization/active_record.rb
|
41
44
|
- lib/mainframe/customization/generic_functions.rb
|
42
45
|
- lib/mainframe/emulators/passport.rb
|
@@ -1,25 +0,0 @@
|
|
1
|
-
defaults: &defaults
|
2
|
-
# The max number of iteration through static screen
|
3
|
-
max_attempts_number: 20
|
4
|
-
session_login_tag: 'EMSP00' # Use a regular expression
|
5
|
-
cics_selection_tag: 'EMSP01' # Use a regular expression
|
6
|
-
cics: ['7', 23, 14] # Text to write at coordinates y, x
|
7
|
-
company_menu: ['01', 24, 43]
|
8
|
-
logoff_cics: 'cesf logoff'
|
9
|
-
company_menu_tag: '\*\* \*\* \*\* \*\*' # Use a regular expression
|
10
|
-
# Starts these transactions from blank cics in order to move forward
|
11
|
-
transactions_cics:
|
12
|
-
company_menu: 'vita'
|
13
|
-
main_application: 'life'
|
14
|
-
#foo: add every variable you need and use it with => ButlerMainframe::Settings.foo
|
15
|
-
# bar: sub variable are accessible with hash => ButlerMainframe::Settings.foo[:bar]
|
16
|
-
|
17
|
-
development:
|
18
|
-
<<: *defaults
|
19
|
-
|
20
|
-
test:
|
21
|
-
<<: *defaults
|
22
|
-
|
23
|
-
production:
|
24
|
-
<<: *defaults
|
25
|
-
cics: ['4', 23, 14]
|