dfhmdf 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +6 -0
- data/Gemspec +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +118 -0
- data/Rakefile +6 -0
- data/bin/dfhmdf +6 -0
- data/dfhmdf.gemspec +23 -0
- data/lib/convert_dfhmdf.rb +66 -0
- data/lib/dfhmdf.rb +126 -0
- data/lib/dfhmdf/version.rb +3 -0
- data/sample-macros +15 -0
- data/spec/lib/dfhmdf/convert_dfhmdf_spec.rb +49 -0
- data/spec/lib/dfhmdf/dfhmdf_spec.rb +208 -0
- data/spec/spec_helper.rb +3 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b63e9ac034b94142ef123c5557fe73b860e0f853
|
4
|
+
data.tar.gz: 749a0b27b492e45c7c83fb9c3588160a6e150b9b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9378f25ada91fd1bc9462d9189133c51c13bbc43d33f32b41cc4a241818b730c36fe41545180109c9d5faa4e658585555313f8c3119951bc461004c2c92ca51c
|
7
|
+
data.tar.gz: aea1f18ac9970760998a21538bfc7622a03110545dbe05cf7351357aae8b88a4753e3104eacca9788da43802125140e656f586f0cde7642959a61c51868602bc
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.lock
|
data/Gemfile
ADDED
data/Gemspec
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Dave Nicolette
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# dfhmdf
|
2
|
+
|
3
|
+
Converts DFHMDF macro specifications into ```text_field``` definitions for use with the (https://github.com/cheezy/te3270/)[TE3270 gem]. The purpose is to eliminate the need for you to count the characters across and down a 3270 screen to determine the X and Y coordinates and the length of each field you wish to define for TE3270.
|
4
|
+
|
5
|
+
## Example
|
6
|
+
|
7
|
+
Given a BMS macro source file named ```myscreen.txt``` with the following contents:
|
8
|
+
|
9
|
+
```
|
10
|
+
QCKSET DFHMSD TYPE=MAP,STORAGE=AUTO,MODE=OUT,LANG=COBOL,TIOAPFX=YES
|
11
|
+
QCKMAP DFHMDI SIZE=(24,80),LINE=1,COLUMN=1,CTRL=ALARM
|
12
|
+
DFHMDF POS=(1,1),LENGTH=3,ATTRB=(ASKIP,BRT),INITIAL='QCK'
|
13
|
+
DFHMDF POS=(1,26),LENGTH=28,ATTRB=(ASKIP,NORM), X
|
14
|
+
INITIAL='Quick Customer Account Check'
|
15
|
+
DFHMDF POS=(3,1),LENGTH=8,ATTRB=(ASKIP,NORM),INITIAL='Account:'
|
16
|
+
ACCTNO DFHMDF POS=(3,13),LENGTH=7,ATTRB=(ASKIP,NORM)
|
17
|
+
DFHMDF POS=(4,1),LENGTH=5,ATTRB=(ASKIP,NORM),INITIAL='Name:'
|
18
|
+
SURNAME DFHMDF POS=(4,13),LENGTH=15,ATTRB=(ASKIP,NORM)
|
19
|
+
FNAME DFHMDF POS=(4,30),LENGTH=10,ATTRB=(ASKIP,NORM)
|
20
|
+
DFHMDF POS=(5,1),LENGTH=11,ATTRB=(ASKIP,NORM),INITIAL='Max charge:'
|
21
|
+
CHG DFHMDF POS=(5,13),ATTRB=(ASKIP,NORM),PICOUT='$,$$0.00'
|
22
|
+
MSG DFHMDF LENGTH=20,POS=(7,1),ATTRB=(ASKIP,NORM)
|
23
|
+
DFHMSD TYPE=FINAL
|
24
|
+
```
|
25
|
+
|
26
|
+
run ```dfhmdf`` as a command-line utility:
|
27
|
+
|
28
|
+
```sh
|
29
|
+
dfhmdf macro-source > target-file
|
30
|
+
```
|
31
|
+
|
32
|
+
to produce the following output:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
text_field(:acctno, 4, 13, 7)
|
36
|
+
text_field(:surname, 5, 13, 15)
|
37
|
+
text_field(:fname, 5, 30, 10)
|
38
|
+
text_field(:chg, 6, 13, 8)
|
39
|
+
text_field(:msg, 8, 1, 20)
|
40
|
+
```
|
41
|
+
|
42
|
+
From the example you may surmise:
|
43
|
+
|
44
|
+
1. It only pays attention to DFHMDF macros.
|
45
|
+
1. It uses the downcased label value as the TE3270 field name, or a name like 'x14y12' for unlabeled DFHMDF macros.
|
46
|
+
1. It adjusts the X axis offset to account for the attribute byte.
|
47
|
+
1. When PICOUT is specified instead of LENGTH, it derives the length from the PICOUT value.
|
48
|
+
1. It generates only ```text_field``` definitions, and not a complete TE3270 screen class.
|
49
|
+
|
50
|
+
So, if you have coded a TE3270 screen class like this:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
class MainframeScreen
|
54
|
+
include TE3270
|
55
|
+
|
56
|
+
def login(username, password)
|
57
|
+
self.userid = username
|
58
|
+
self.password = password
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
emulator = TE3270.emulator_for :extra do |platform|
|
63
|
+
platform.session_file = 'sessionfile.edp'
|
64
|
+
end
|
65
|
+
my_screen = MainframeScreen.new(emulator)
|
66
|
+
my_screen.userid = 'the_id'
|
67
|
+
my_screen.password = 'the_password'
|
68
|
+
```
|
69
|
+
|
70
|
+
then you can paste in the generated ```text_field``` definitions like this:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class MainframeScreen
|
74
|
+
include TE3270
|
75
|
+
|
76
|
+
text_field(:acctno, 4, 13, 7)
|
77
|
+
text_field(:surname, 5, 13, 15)
|
78
|
+
text_field(:fname, 5, 30, 10)
|
79
|
+
text_field(:chg, 6, 13, 8)
|
80
|
+
text_field(:msg, 8, 1, 20)
|
81
|
+
|
82
|
+
def login(username, password)
|
83
|
+
self.userid = username
|
84
|
+
self.password = password
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
emulator = TE3270.emulator_for :extra do |platform|
|
89
|
+
platform.session_file = 'sessionfile.edp'
|
90
|
+
end
|
91
|
+
my_screen = MainframeScreen.new(emulator)
|
92
|
+
my_screen.userid = 'the_id'
|
93
|
+
my_screen.password = 'the_password'
|
94
|
+
```
|
95
|
+
|
96
|
+
## Installation
|
97
|
+
|
98
|
+
Add this line to your application's Gemfile:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
gem 'dfhmdf'
|
102
|
+
```
|
103
|
+
|
104
|
+
And then execute:
|
105
|
+
|
106
|
+
$ bundle
|
107
|
+
|
108
|
+
or install it yourself as:
|
109
|
+
|
110
|
+
$ gem install dfhmdf
|
111
|
+
|
112
|
+
## Contributing
|
113
|
+
|
114
|
+
1. Fork it ( https://github.com/[my-github-username]/dfhmdf/fork )
|
115
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
116
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
117
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
118
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/dfhmdf
ADDED
data/dfhmdf.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dfhmdf/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dfhmdf"
|
8
|
+
spec.version = Dfhmdf::VERSION
|
9
|
+
spec.authors = ["Dave Nicolette"]
|
10
|
+
spec.email = ["davenicolette@gmail.com"]
|
11
|
+
spec.summary = %q{Interprets DFHMDF macros}
|
12
|
+
spec.description = %q{Generate text_field specifications for te3270 based on DFHMDF source}
|
13
|
+
spec.homepage = "http://github.com/neopragma/dfhmdf"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative './dfhmdf'
|
2
|
+
|
3
|
+
class ConvertDfhmdf
|
4
|
+
include Dfhmdf
|
5
|
+
|
6
|
+
def run
|
7
|
+
open_file
|
8
|
+
begin
|
9
|
+
clear
|
10
|
+
ingest_macro
|
11
|
+
process_macro @macro_source
|
12
|
+
puts te3270_text_field if dfhmdf?
|
13
|
+
end while @eof == false
|
14
|
+
close_file
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_macro dfhmdf_macro
|
18
|
+
parse_tokens tokenize_line dfhmdf_macro
|
19
|
+
end
|
20
|
+
|
21
|
+
def ingest_macro
|
22
|
+
macro_end = false
|
23
|
+
@macro_source = ''
|
24
|
+
current_line = read_line
|
25
|
+
begin
|
26
|
+
if current_line == nil || current_line.length < 72 || current_line[71] == ' '
|
27
|
+
macro_end = true
|
28
|
+
end
|
29
|
+
@macro_source << squish(current_line)
|
30
|
+
current_line = read_line unless macro_end
|
31
|
+
end while macro_end == false
|
32
|
+
@macro_source
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_macro dfhmdf_macro
|
36
|
+
parse_tokens tokenize_line dfhmdf_macro
|
37
|
+
end
|
38
|
+
|
39
|
+
def squish str
|
40
|
+
str[71] = ' ' unless str.length < 72
|
41
|
+
str.split.join(' ')
|
42
|
+
end
|
43
|
+
|
44
|
+
def macro_source
|
45
|
+
@macro_source
|
46
|
+
end
|
47
|
+
|
48
|
+
def read_line
|
49
|
+
line = @source_file.readline
|
50
|
+
@eof = @source_file.eof?
|
51
|
+
line
|
52
|
+
end
|
53
|
+
|
54
|
+
def open_file
|
55
|
+
if ARGV[0] == nil
|
56
|
+
abort 'Usage: ruby make_fields.rb inputfilename'
|
57
|
+
end
|
58
|
+
@source_file = File.open(ARGV[0], 'r')
|
59
|
+
@eof = false
|
60
|
+
end
|
61
|
+
|
62
|
+
def close_file
|
63
|
+
@source_file.close
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
data/lib/dfhmdf.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
module Dfhmdf
|
2
|
+
|
3
|
+
def te3270_text_field
|
4
|
+
"text_field(:#{field_label}, #{x_coordinate}, #{y_coordinate}, #{field_length})"
|
5
|
+
end
|
6
|
+
|
7
|
+
def clear
|
8
|
+
@field_label, @parameter_hash, @parameters, @tokens = nil
|
9
|
+
@dfhmdf = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def tokenize_line input_line
|
13
|
+
|
14
|
+
# Want to split on spaces except when space occurs within single quotes.
|
15
|
+
# Should be able to do it with a regex. Unable to figure it out so far. Using brute force.
|
16
|
+
# This regex doesn't work but was as close as I was able to get.
|
17
|
+
# @tokens = [@tokens, input_line.scan(/'.*?'|".*?"|\S+/)].compact.reduce([], :|)
|
18
|
+
|
19
|
+
new_tokens = []
|
20
|
+
temp = input_line.split
|
21
|
+
for i in 0..temp.length-1 do
|
22
|
+
if temp[i] != nil
|
23
|
+
if temp[i].include? "'"
|
24
|
+
temp[i] << ' ' << temp[i+1] unless temp[i+1] == nil
|
25
|
+
temp[i + 1] = nil
|
26
|
+
if new_tokens[i] == nil
|
27
|
+
new_tokens[i] = temp[i]
|
28
|
+
else
|
29
|
+
new_tokens[i] << temp[i]
|
30
|
+
end
|
31
|
+
else
|
32
|
+
new_tokens << temp[i]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
@tokens = [@tokens, new_tokens].compact.reduce([], :|)
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_tokens tokens
|
40
|
+
@dfhmdf = false
|
41
|
+
if tokens[0] == 'DFHMDF'
|
42
|
+
@dfhmdf = true
|
43
|
+
@field_label = nil
|
44
|
+
operands = tokens[1]
|
45
|
+
elsif tokens[1] == 'DFHMDF'
|
46
|
+
@dfhmdf = true
|
47
|
+
@field_label = tokens[0].downcase
|
48
|
+
operands = tokens[2]
|
49
|
+
end
|
50
|
+
if dfhmdf? && tokens != nil && operands != nil && operands.include?('=')
|
51
|
+
parse_operands operands
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
def parse_operands operands_as_string
|
57
|
+
#-----------------------------------------------------------------------------
|
58
|
+
# Parse the operands in a macro source statement:
|
59
|
+
#
|
60
|
+
# LABEL MACRO OPERAND,OPERAND,OPERAND COMMENT X
|
61
|
+
# xxxxxxxxxxxxxxxxxxxxxxx
|
62
|
+
#
|
63
|
+
# Example
|
64
|
+
# -------
|
65
|
+
# from this...
|
66
|
+
# FIELD1 DFHMDF POS=(6,18),LENGTH=14,ATTRB=(ASKIP,NORM),INITIAL='Hello there'
|
67
|
+
#
|
68
|
+
# to this...
|
69
|
+
# { :pos => [ "6", "18" ], :length => "14", :attrb => [ "ASKIP", "NORM" ],
|
70
|
+
# :initial => "Hello there" }
|
71
|
+
#-----------------------------------------------------------------------------
|
72
|
+
@operands_hash = {}
|
73
|
+
|
74
|
+
# Split on comma except when the comma appears within parentheses.
|
75
|
+
# Couldn't figure out how to make it ignore commas within single quotes,
|
76
|
+
# so it misses PICOUT='$,$$0.00' and similar. Using brute force to handle it.
|
77
|
+
|
78
|
+
item = operands_as_string.split(/,(?![^(]*\))/)
|
79
|
+
for i in 0..item.length-1
|
80
|
+
if item[i].match(/^PICOUT=/)
|
81
|
+
item[i] << ',' << item[i+1]
|
82
|
+
end
|
83
|
+
|
84
|
+
if item[i].include? '='
|
85
|
+
key_value_pair = item[i].split('=')
|
86
|
+
|
87
|
+
# handle operand values consisting of a comma-separated list within parentheses
|
88
|
+
if key_value_pair[1][0] == '('
|
89
|
+
key_value_pair[1].gsub!(/[\(\)]/, '')
|
90
|
+
key_value_pair[1] = key_value_pair[1].split(',')
|
91
|
+
end
|
92
|
+
|
93
|
+
# handle operand values in single quotes
|
94
|
+
if key_value_pair[1][0] == "'"
|
95
|
+
key_value_pair[1].gsub!(/'/, '')
|
96
|
+
end
|
97
|
+
|
98
|
+
@operands_hash[key_value_pair[0].downcase.to_sym] = key_value_pair[1]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
@operands_hash
|
102
|
+
end
|
103
|
+
|
104
|
+
def x_coordinate
|
105
|
+
(@operands_hash != nil && @operands_hash[:pos] && @operands_hash[:pos][0].to_i + 1) || 0
|
106
|
+
end
|
107
|
+
|
108
|
+
def y_coordinate
|
109
|
+
(@operands_hash != nil && @operands_hash[:pos] && @operands_hash[:pos][1].to_i) || 0
|
110
|
+
end
|
111
|
+
|
112
|
+
def field_length
|
113
|
+
(@operands_hash != nil && @operands_hash[:length] && @operands_hash[:length].to_i) ||
|
114
|
+
(@operands_hash != nil && @operands_hash[:initial] && @operands_hash[:initial].length) ||
|
115
|
+
(@operands_hash != nil && @operands_hash[:picout] && @operands_hash[:picout].length) || 0
|
116
|
+
end
|
117
|
+
|
118
|
+
def field_label
|
119
|
+
(@field_label == nil && "x#{x_coordinate}y#{y_coordinate}") || @field_label
|
120
|
+
end
|
121
|
+
|
122
|
+
def dfhmdf?
|
123
|
+
@dfhmdf
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
data/sample-macros
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
QCKSET DFHMSD TYPE=MAP,STORAGE=AUTO,MODE=OUT,LANG=COBOL,TIOAPFX=YES
|
2
|
+
QCKMAP DFHMDI SIZE=(24,80),LINE=1,COLUMN=1,CTRL=ALARM
|
3
|
+
DFHMDF POS=(1,1),LENGTH=3,ATTRB=(ASKIP,BRT),INITIAL='QCK'
|
4
|
+
TITLE DFHMDF POS=(1,26),LENGTH=28,ATTRB=(ASKIP,NORM), X
|
5
|
+
INITIAL='Quick Customer Account Check'
|
6
|
+
HEAD DFHMDF POS=(3,1),LENGTH=8,ATTRB=(ASKIP,NORM),INITIAL='Account:'
|
7
|
+
ACCTNO DFHMDF POS=(3,13),LENGTH=7,ATTRB=(ASKIP,NORM)
|
8
|
+
DFHMDF POS=(4,1),LENGTH=5,ATTRB=(ASKIP,NORM),INITIAL='Name:'
|
9
|
+
SURNAME DFHMDF POS=(4,13),LENGTH=15,ATTRB=(ASKIP,NORM)
|
10
|
+
FNAME DFHMDF POS=(4,30),LENGTH=10,ATTRB=(ASKIP,NORM)
|
11
|
+
DFHMDF POS=(5,1),LENGTH=11,ATTRB=(ASKIP,NORM), X
|
12
|
+
INITIAL='Max charge:'
|
13
|
+
CHG DFHMDF POS=(5,13),ATTRB=(ASKIP,NORM),PICOUT='$,$$0.00'
|
14
|
+
MSG DFHMDF LENGTH=20,POS=(7,1),ATTRB=(ASKIP,NORM)
|
15
|
+
DFHMSD TYPE=FINAL
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'convert_dfhmdf'
|
2
|
+
|
3
|
+
describe ConvertDfhmdf do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@screen_def = ConvertDfhmdf.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#process_macro" do
|
10
|
+
it "handles a DFHMDF macro" do
|
11
|
+
@screen_def.process_macro 'SURNAME DFHMDF POS=(4,13),LENGTH=15,ATTRB=(ASKIP,NORM)'
|
12
|
+
expect(@screen_def.dfhmdf?).to be(true)
|
13
|
+
expect(@screen_def.field_label).to eq('surname')
|
14
|
+
expect(@screen_def.x_coordinate).to eq(5)
|
15
|
+
expect(@screen_def.y_coordinate).to eq(13)
|
16
|
+
expect(@screen_def.field_length).to eq(15)
|
17
|
+
end
|
18
|
+
it "ignores macros other than DFHMDF" do
|
19
|
+
@screen_def.process_macro 'QCKSET DFHMSD TYPE=MAP,STORAGE=AUTO,MODE=OUT,LANG=COBOL,TIOAPFX=YES'
|
20
|
+
expect(@screen_def.dfhmdf?).to be(false)
|
21
|
+
expect(@screen_def.field_label).to eq('x0y0')
|
22
|
+
expect(@screen_def.x_coordinate).to eq(0)
|
23
|
+
expect(@screen_def.y_coordinate).to eq(0)
|
24
|
+
expect(@screen_def.field_length).to eq(0)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#ingest_macro" do
|
29
|
+
it "stores macro source coded on a single line" do
|
30
|
+
allow(@screen_def).to receive(:read_line).and_return('SURNAME DFHMDF POS=(4,13),LENGTH=15,ATTRB=(ASKIP,NORM)')
|
31
|
+
@screen_def.ingest_macro
|
32
|
+
expect(@screen_def.macro_source).to eq('SURNAME DFHMDF POS=(4,13),LENGTH=15,ATTRB=(ASKIP,NORM)')
|
33
|
+
end
|
34
|
+
|
35
|
+
it "stores macro source coded on multiple lines" do
|
36
|
+
allow(@screen_def).to receive(:read_line).and_return(
|
37
|
+
# 1 2 3 4 5 6 7 8
|
38
|
+
# 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
39
|
+
'SURNAME DFHMDF POS=(4,13), X',
|
40
|
+
' LENGTH=15, X',
|
41
|
+
' ATTRB=(ASKIP,NORM), X',
|
42
|
+
' INITIAL=\'Name here\'')
|
43
|
+
@screen_def.ingest_macro
|
44
|
+
expect(@screen_def.macro_source)
|
45
|
+
.to eq('SURNAME DFHMDF POS=(4,13),LENGTH=15,ATTRB=(ASKIP,NORM),INITIAL=\'Name here\'')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
require 'dfhmdf'
|
2
|
+
|
3
|
+
class ScreenDef
|
4
|
+
include Dfhmdf
|
5
|
+
|
6
|
+
def operands_hash value
|
7
|
+
@operands_hash = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def field_label= value
|
11
|
+
@field_label = value
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ScreenDef do
|
17
|
+
|
18
|
+
before(:each) do
|
19
|
+
@screen_def = ScreenDef.new
|
20
|
+
end
|
21
|
+
|
22
|
+
context "housekeeping" do
|
23
|
+
it "clears all temporary values relevant to processing a DFHMDF macro" do
|
24
|
+
@screen_def.clear
|
25
|
+
expect(@screen_def.dfhmdf?).to be(false)
|
26
|
+
expect(@screen_def.field_length).to eq(0)
|
27
|
+
expect(@screen_def.field_label).to eq('x0y0')
|
28
|
+
expect(@screen_def.x_coordinate).to eq(0)
|
29
|
+
expect(@screen_def.y_coordinate).to eq(0)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "tokenizing" do
|
34
|
+
describe "#tokenize_line" do
|
35
|
+
it "collects tokens separated by spaces" do
|
36
|
+
expect(@screen_def.tokenize_line('abc de,fg,hijk lmnop'))
|
37
|
+
.to eq([ 'abc', 'de,fg,hijk', 'lmnop' ])
|
38
|
+
end
|
39
|
+
|
40
|
+
it "doesn't split on spaces that appear within quoted strings" do
|
41
|
+
expect(@screen_def.tokenize_line("abc de,'fg hi',jkl mnop"))
|
42
|
+
.to eq([ "abc", "de,'fg hi',jkl", "mnop" ])
|
43
|
+
end
|
44
|
+
|
45
|
+
it "splits properly when the last operand is a quoted string with a space" do
|
46
|
+
expect(@screen_def.tokenize_line("abc de,'fg hi',jkl"))
|
47
|
+
.to eq([ "abc", "de,'fg hi',jkl" ])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "recognizing DFHMDF macros" do
|
53
|
+
describe "#parse_tokens" do
|
54
|
+
it "recognizes a DFHMDF macro with no label" do
|
55
|
+
@screen_def.parse_tokens([ 'DFHMDF', 'POS=(4,5),LENGTH=15', 'baz' ])
|
56
|
+
expect(@screen_def.dfhmdf?).to be(true)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#parse_tokens" do
|
61
|
+
it "clears the previous value of field label when none is specified" do
|
62
|
+
@screen_def.field_label = 'aardvaark'
|
63
|
+
@screen_def.parse_tokens([ 'DFHMDF', 'foo', 'bar' ])
|
64
|
+
expect(@screen_def.field_label).to eql('x0y0')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#parse_tokens" do
|
69
|
+
it "recognizes a DFHMDF macro with a label" do
|
70
|
+
@screen_def.parse_tokens([ 'FIELDNAME', 'DFHMDF', 'POS=(4,5),LENGTH=15', 'bar' ])
|
71
|
+
expect(@screen_def.dfhmdf?).to be(true)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#parse_tokens" do
|
76
|
+
it "populates the field label when one is specified" do
|
77
|
+
@screen_def.parse_tokens([ 'FIELDNAME', 'DFHMDF', 'POS=(4,5),LENGTH=15', 'bar' ])
|
78
|
+
expect(@screen_def.field_label).to eq('fieldname')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#parse_tokens" do
|
83
|
+
it "ignores source lines that do not contain a DFHMDF macro" do
|
84
|
+
@screen_def.parse_tokens [ 'foo', 'bar', 'DFHMDF', 'baz' ]
|
85
|
+
expect(@screen_def.dfhmdf?).to eq(false)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "parsing macro operands" do
|
91
|
+
describe "#parse_operands" do
|
92
|
+
it "handles simple key-value pairs" do
|
93
|
+
expect(@screen_def.parse_operands("KEY1=15,KEY2=30"))
|
94
|
+
.to eq({ :key1 => "15", :key2 => "30" })
|
95
|
+
end
|
96
|
+
|
97
|
+
it "handles operands with quoted values" do
|
98
|
+
expect(@screen_def.parse_operands("KEY1='Quoted value 1',KEY2='Quoted value 2'"))
|
99
|
+
.to eq({ :key1 => "Quoted value 1", :key2 => "Quoted value 2" })
|
100
|
+
end
|
101
|
+
|
102
|
+
it "handles operands with comma-separated values in parentheses" do
|
103
|
+
expect(@screen_def.parse_operands("KEY1=(one,two),KEY2=(three,four)"))
|
104
|
+
.to eq({ :key1 => [ "one", "two" ], :key2 => [ "three", "four" ] })
|
105
|
+
end
|
106
|
+
|
107
|
+
it "handles a mix of operand formats" do
|
108
|
+
expect(@screen_def.parse_operands("POS=(6,18),LENGTH=14,ATTRB=(ASKIP,NORM),INITIAL='Hello there'"))
|
109
|
+
.to eq({ :pos => [ "6", "18" ], :length => "14", :attrb => [ "ASKIP", "NORM" ], :initial => "Hello there" })
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "determining field label" do
|
115
|
+
describe "#field_label" do
|
116
|
+
it "returns the field label that was specified on the DFHMDF macro" do
|
117
|
+
@screen_def.field_label = 'NAME'
|
118
|
+
expect(@screen_def.field_label).to eq('NAME')
|
119
|
+
end
|
120
|
+
|
121
|
+
it "derives a field label based on x and y coordinates when no label was specified" do
|
122
|
+
@screen_def.field_label = nil
|
123
|
+
@screen_def.operands_hash( { :pos => [ "5", "18" ] })
|
124
|
+
expect(@screen_def.field_label).to eq('x6y18')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context "determining field position" do
|
130
|
+
describe "#x_coordinate" do
|
131
|
+
it "returns 0 as the x coordinate if the position has not been determined" do
|
132
|
+
expect(@screen_def.x_coordinate).to eq(0)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "returns 0 as the x coordinate if POS=(x,y) was not specified" do
|
136
|
+
@screen_def.operands_hash( { :foo => "bar" } )
|
137
|
+
expect(@screen_def.x_coordinate).to eq(0)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "calculates the x coordinate value skipping the attribute byte" do
|
141
|
+
@screen_def.operands_hash( { :pos => ["5", "28"] } )
|
142
|
+
expect(@screen_def.x_coordinate).to eq(6)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "#y_coordinate" do
|
147
|
+
it "returns 0 as the y coordinate if the position has not been determined" do
|
148
|
+
expect(@screen_def.y_coordinate).to eq(0)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "returns 0 as the y coordinate if POS=(x,y) was not specified" do
|
152
|
+
@screen_def.operands_hash( { :foo => "bar" } )
|
153
|
+
expect(@screen_def.y_coordinate).to eq(0)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "returns the y coordinate value from the POS=(x,y) parameter" do
|
157
|
+
@screen_def.operands_hash( { :pos => ["5", "28"] } )
|
158
|
+
expect(@screen_def.y_coordinate).to eq(28)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "determining field length" do
|
164
|
+
describe "handling the LENGTH= parameter of the DFHMDF macro" do
|
165
|
+
it "returns 0 as the length if the length has not been determined" do
|
166
|
+
expect(@screen_def.field_length).to eq(0)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "returns 0 as the length if the length was not specified" do
|
170
|
+
@screen_def.operands_hash( { :foo => "bar" } )
|
171
|
+
expect(@screen_def.field_length).to eq(0)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "returns the length value from the LENGTH= parameter" do
|
175
|
+
@screen_def.operands_hash( { :length => "34" })
|
176
|
+
expect(@screen_def.field_length).to eq(34)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "handling the PICOUT= parameter of the DFHMDF macro" do
|
181
|
+
it "derives the length based on the PICOUT value" do
|
182
|
+
@screen_def.operands_hash( { :picout => "$,$$0.00" })
|
183
|
+
expect(@screen_def.field_length).to eq(8)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe "generating a text_field definition" do
|
189
|
+
it "generates a text_field definition for a field with a LENGTH= specification" do
|
190
|
+
@screen_def.field_label = 'myfield'
|
191
|
+
@screen_def.operands_hash({ :pos => [ "23", "6" ], :length => "14" })
|
192
|
+
expect(@screen_def.te3270_text_field).to eql('text_field(:myfield, 24, 6, 14)')
|
193
|
+
end
|
194
|
+
|
195
|
+
it "generates a text_field definition for a field with a PICOUT= specification" do
|
196
|
+
@screen_def.field_label = 'otherfld'
|
197
|
+
@screen_def.operands_hash({ :pos => [ "8", "16" ], :picout => "$$,$$0.00" })
|
198
|
+
expect(@screen_def.te3270_text_field).to eql('text_field(:otherfld, 9, 16, 9)')
|
199
|
+
end
|
200
|
+
|
201
|
+
it "generates a text_field definition for a field with INITIAL= and no LENGTH=" do
|
202
|
+
@screen_def.field_label = 'otherfld'
|
203
|
+
@screen_def.operands_hash({ :pos => [ "8", "16" ], :initial => "Hello" })
|
204
|
+
expect(@screen_def.te3270_text_field).to eql('text_field(:otherfld, 9, 16, 5)')
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dfhmdf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dave Nicolette
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Generate text_field specifications for te3270 based on DFHMDF source
|
42
|
+
email:
|
43
|
+
- davenicolette@gmail.com
|
44
|
+
executables:
|
45
|
+
- dfhmdf
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- .gitignore
|
50
|
+
- Gemfile
|
51
|
+
- Gemspec
|
52
|
+
- LICENSE.txt
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- bin/dfhmdf
|
56
|
+
- dfhmdf.gemspec
|
57
|
+
- lib/convert_dfhmdf.rb
|
58
|
+
- lib/dfhmdf.rb
|
59
|
+
- lib/dfhmdf/version.rb
|
60
|
+
- sample-macros
|
61
|
+
- spec/lib/dfhmdf/convert_dfhmdf_spec.rb
|
62
|
+
- spec/lib/dfhmdf/dfhmdf_spec.rb
|
63
|
+
- spec/spec_helper.rb
|
64
|
+
homepage: http://github.com/neopragma/dfhmdf
|
65
|
+
licenses:
|
66
|
+
- MIT
|
67
|
+
metadata: {}
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 2.2.2
|
85
|
+
signing_key:
|
86
|
+
specification_version: 4
|
87
|
+
summary: Interprets DFHMDF macros
|
88
|
+
test_files:
|
89
|
+
- spec/lib/dfhmdf/convert_dfhmdf_spec.rb
|
90
|
+
- spec/lib/dfhmdf/dfhmdf_spec.rb
|
91
|
+
- spec/spec_helper.rb
|