butler-mainframe 0.5.0 → 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/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]
|