stats_package_syntax_file_generator 1.0.4 → 1.1.3
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 +5 -5
- data/README +2 -1
- data/lib/stats_package_syntax_file_generator.rb +1 -0
- data/lib/syntax_file/controller.rb +214 -220
- data/lib/syntax_file/maker.rb +92 -92
- data/lib/syntax_file/maker_rddi.rb +55 -0
- data/lib/syntax_file/maker_sas.rb +204 -205
- data/lib/syntax_file/maker_spss.rb +143 -143
- data/lib/syntax_file/maker_stata.rb +211 -192
- data/lib/syntax_file/maker_sts.rb +120 -127
- data/lib/syntax_file/value.rb +15 -16
- data/lib/syntax_file/variable.rb +40 -41
- data/tests/input_all_vars.yaml +1 -1
- data/tests/input_controller.yaml +1 -1
- data/tests/setup.rb +8 -8
- data/tests/tc_controller.rb +1 -1
- data/tests/tc_maker.rb +1 -1
- data/tests/tc_maker_rddi.rb +33 -0
- data/tests/tc_maker_stata.rb +1 -1
- data/tests/tc_maker_sts.rb +0 -1
- data/tests/ts_all.rb +1 -0
- metadata +5 -4
data/lib/syntax_file/maker.rb
CHANGED
@@ -4,123 +4,123 @@
|
|
4
4
|
# https://github.com/mnpopcenter/stats_package_syntax_file_generator
|
5
5
|
|
6
6
|
module SyntaxFile
|
7
|
-
class Maker
|
7
|
+
class Maker
|
8
8
|
|
9
|
-
attr_reader
|
10
|
-
attr_accessor :cmd_end
|
11
|
-
|
12
|
-
def initialize (sfc, syntax_type)
|
13
|
-
@sfc = sfc
|
14
|
-
@syntax_type = syntax_type
|
15
|
-
@cmd_end = ''
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
# Syntax terminator.
|
20
|
-
|
21
|
-
def syntax_end
|
22
|
-
[ @cmd_end, blank ]
|
23
|
-
end
|
24
|
-
|
25
|
-
def blank
|
26
|
-
''
|
27
|
-
end
|
9
|
+
attr_reader :sfc, :syntax_type
|
10
|
+
attr_accessor :cmd_end
|
28
11
|
|
12
|
+
def initialize(sfc, syntax_type)
|
13
|
+
@sfc = sfc
|
14
|
+
@syntax_type = syntax_type
|
15
|
+
@cmd_end = ''
|
16
|
+
end
|
29
17
|
|
30
|
-
#
|
18
|
+
# Syntax terminator.
|
31
19
|
|
32
|
-
def
|
33
|
-
|
34
|
-
end
|
20
|
+
def syntax_end
|
21
|
+
[@cmd_end, blank]
|
22
|
+
end
|
35
23
|
|
36
|
-
def
|
37
|
-
|
38
|
-
end
|
24
|
+
def blank
|
25
|
+
''
|
26
|
+
end
|
39
27
|
|
40
|
-
|
41
|
-
# Write a value in a syntax file varies by variable type:
|
42
|
-
# - Numeric variable: simply return the value as a string.
|
43
|
-
# - String variable: zero-pad the value if it looks like an integer.
|
44
|
-
v = val_orig.to_s
|
45
|
-
return v unless var.is_string_var
|
46
|
-
return v unless v =~ /^\-?\d+$/
|
47
|
-
sprintf('%0' + var.width.to_s + 'i', v.to_i)
|
48
|
-
end
|
28
|
+
# Quoting methods.
|
49
29
|
|
30
|
+
def q(s)
|
31
|
+
'"' + s.to_s.gsub('"', '""') + '"'
|
32
|
+
end
|
50
33
|
|
51
|
-
|
34
|
+
def val_q(var, v)
|
35
|
+
var.is_string_var ? q(v) : v.to_s
|
36
|
+
end
|
52
37
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
38
|
+
def val_as_s(var, val_orig)
|
39
|
+
# Write a value in a syntax file varies by variable type:
|
40
|
+
# - Numeric variable: simply return the value as a string.
|
41
|
+
# - String variable: zero-pad the value if it looks like an integer.
|
42
|
+
v = val_orig.to_s
|
43
|
+
return v unless var.is_string_var
|
44
|
+
return v unless v =~ /^\-?\d+$/
|
45
|
+
sprintf('%0' + var.width.to_s + 'i', v.to_i)
|
46
|
+
end
|
56
47
|
|
57
|
-
|
58
|
-
# Takes a string and a max length.
|
59
|
-
# Returns the array of strings that results from chopping the
|
60
|
-
# original string into segments no longer than max length.
|
61
|
-
# This is needed because some stats packages have max line lengths.
|
62
|
-
label = label.to_s
|
63
|
-
return [label] if label.length <= max_length
|
64
|
-
label = String.new(label)
|
65
|
-
r = []
|
66
|
-
r.push( label.slice!(0,max_length) ) while label.length > 0
|
67
|
-
r
|
68
|
-
end
|
48
|
+
# Methods to deal with long labels.
|
69
49
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
# by the stats package). The purpose of the function is to handle
|
74
|
-
# long values and labels for stats packages that have a max syntax
|
75
|
-
# line length. See unit tests for an illustration.
|
76
|
-
r = []
|
77
|
-
r.push(sprintf(fmt, a.shift, op_c, '' )) while a.size > 1
|
78
|
-
r.push(sprintf(fmt, a.shift, op_a, b.shift))
|
79
|
-
r.push(sprintf(fmt, '', op_c, b.shift)) while b.size > 0
|
80
|
-
r
|
81
|
-
end
|
50
|
+
def label_trunc(label, limit)
|
51
|
+
label.to_s[0, limit]
|
52
|
+
end
|
82
53
|
|
54
|
+
def label_segments(label, max_length)
|
55
|
+
# Takes a string and a max length.
|
56
|
+
# Returns the array of strings that results from chopping the
|
57
|
+
# original string into segments no longer than max length.
|
58
|
+
# This is needed because some stats packages have max line lengths.
|
59
|
+
label = label.to_s
|
60
|
+
return [label] if label.length <= max_length
|
61
|
+
label = String.new(label)
|
62
|
+
r = []
|
63
|
+
r.push(label.slice!(0, max_length)) while label.length > 0
|
64
|
+
r
|
65
|
+
end
|
83
66
|
|
84
|
-
|
67
|
+
def weave_label_segments(fmt, a, b, op_a, op_c)
|
68
|
+
# The function takes a sprintf format, two lists (a, b), and
|
69
|
+
# two strings (the assignment and concatenation operators used
|
70
|
+
# by the stats package). The purpose of the function is to handle
|
71
|
+
# long values and labels for stats packages that have a max syntax
|
72
|
+
# line length. See unit tests for an illustration.
|
73
|
+
r = []
|
74
|
+
r.push(sprintf(fmt, a.shift, op_c, '')) while a.size > 1
|
75
|
+
r.push(sprintf(fmt, a.shift, op_a, b.shift))
|
76
|
+
r.push(sprintf(fmt, '', op_c, b.shift)) while b.size > 0
|
77
|
+
r
|
78
|
+
end
|
85
79
|
|
86
|
-
|
87
|
-
# For non-string variables, only values that look
|
88
|
-
# like integers can be labeled.
|
89
|
-
return var.values if var.is_string_var
|
90
|
-
var.values.find_all { |val| val.value.to_s =~ /^\-?\d+$/ }
|
91
|
-
end
|
80
|
+
# Helper methods for values and their labels.
|
92
81
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
|
82
|
+
def labelable_values(var)
|
83
|
+
# For non-string variables, only values that look
|
84
|
+
# like integers can be labeled.
|
85
|
+
return var.values if var.is_string_var
|
86
|
+
var.values.find_all { |val| val.value.to_s =~ /^\-?\d+$/ }
|
87
|
+
end
|
97
88
|
|
89
|
+
def max_value_length(var, val_list)
|
90
|
+
return 0 if val_list.empty?
|
91
|
+
val_list.map { |val| val_as_s(var, val.value).length }.max
|
92
|
+
end
|
98
93
|
|
99
|
-
# Methods for comments at the start or end of the syntax file.
|
94
|
+
# Methods for comments at the start or end of the syntax file.
|
100
95
|
|
101
|
-
def comments_start
|
102
|
-
|
103
|
-
|
96
|
+
def comments_start
|
97
|
+
# Comments not needed unless syntax file is for the web app.
|
98
|
+
return [] unless @sfc.caller == 'web_app'
|
104
99
|
|
105
|
-
|
100
|
+
return [
|
106
101
|
'NOTE: You need to set the Stata working directory to the path',
|
107
102
|
'where the data file is located.',
|
108
|
-
|
103
|
+
] if @syntax_type == 'stata'
|
104
|
+
|
105
|
+
return [
|
106
|
+
"NOTE: To load data, you must download both the extract's data and the DDI",
|
107
|
+
"and also set the working directory to the folder with these files (or change the path below).",
|
108
|
+
] if @syntax_type == 'rddi'
|
109
109
|
|
110
|
-
|
111
|
-
|
110
|
+
cmd = (@syntax_type == 'sas') ? 'libname' : 'cd'
|
111
|
+
result = [
|
112
112
|
"NOTE: You need to edit the `#{cmd}` command to specify the path to the directory",
|
113
113
|
'where the data file is located. For example: "C:\ipums_directory".'
|
114
|
-
|
115
|
-
|
116
|
-
|
114
|
+
]
|
115
|
+
if @syntax_type == 'sas'
|
116
|
+
result << "Edit the `filename` command similarly to include the full path (the directory and the data file name)."
|
117
|
+
end
|
118
|
+
result
|
117
119
|
end
|
118
|
-
result
|
119
|
-
end
|
120
120
|
|
121
|
-
def comments_end
|
122
|
-
|
123
|
-
end
|
121
|
+
def comments_end
|
122
|
+
[]
|
123
|
+
end
|
124
124
|
|
125
|
-
end
|
125
|
+
end
|
126
126
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# This file is part of the Minnesota Population Center's stats_package_syntax_file_generator project.
|
2
|
+
# For copyright and licensing information, see the NOTICE and LICENSE files
|
3
|
+
# in this project's top-level directory, and also on-line at:
|
4
|
+
# https://github.com/mnpopcenter/stats_package_syntax_file_generator
|
5
|
+
|
6
|
+
module SyntaxFile
|
7
|
+
class MakerRDDI < Maker
|
8
|
+
|
9
|
+
def initialize(sfc, syntax_type)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def syntax
|
14
|
+
r = [
|
15
|
+
comments_start,
|
16
|
+
check_pkg,
|
17
|
+
syn_df,
|
18
|
+
comments_end,
|
19
|
+
]
|
20
|
+
r.flatten
|
21
|
+
end
|
22
|
+
|
23
|
+
def comments_start
|
24
|
+
convert_to_comments(super)
|
25
|
+
end
|
26
|
+
|
27
|
+
def comments_end
|
28
|
+
convert_to_comments(super)
|
29
|
+
end
|
30
|
+
|
31
|
+
def convert_to_comments(lines)
|
32
|
+
return [] if lines.empty?
|
33
|
+
[
|
34
|
+
lines.map { |ln| '# ' + ln },
|
35
|
+
blank,
|
36
|
+
].flatten
|
37
|
+
end
|
38
|
+
|
39
|
+
def check_pkg
|
40
|
+
[
|
41
|
+
'if (!require("ipumsr")) stop("Reading IPUMS data into R requires the ipumsr package. It can be installed using the following command: install.packages(\'ipumsr\')")',
|
42
|
+
''
|
43
|
+
]
|
44
|
+
end
|
45
|
+
|
46
|
+
def syn_df
|
47
|
+
ddi_file = @sfc.data_file_name.chomp[0...-3] + 'xml'
|
48
|
+
[
|
49
|
+
'ddi <- read_ipums_ddi(' + q(ddi_file) + ')',
|
50
|
+
'data <- read_ipums_micro(ddi)',
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -4,27 +4,27 @@
|
|
4
4
|
# https://github.com/mnpopcenter/stats_package_syntax_file_generator
|
5
5
|
|
6
6
|
module SyntaxFile
|
7
|
-
class MakerSAS < Maker
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
7
|
+
class MakerSAS < Maker
|
8
|
+
|
9
|
+
def initialize(sfc, syntax_type)
|
10
|
+
super
|
11
|
+
m = @sfc.max_var_name_length
|
12
|
+
@var_loc_format = " %-#{m}s "
|
13
|
+
@var_lab_format = " %-#{m}s %s %s"
|
14
|
+
@fmt_link_format = " %-#{m}s %s."
|
15
|
+
@bignum_int_format = " %-#{m}s %d."
|
16
|
+
@bignum_dec_format = " %-#{m}s %d.%d"
|
17
|
+
@cmd_end = ';'
|
18
|
+
@label_max_leng = 256
|
19
|
+
@segment_max_leng = 100
|
20
|
+
@sas_library_handle = 'IPUMS'
|
21
|
+
@sas_file_handle = 'ASCIIDAT'
|
22
|
+
@sas_fmt_suffix = '_f'
|
23
|
+
@sas_data_file_name = @sas_library_handle + '.' + @sfc.data_file_name_stem
|
24
|
+
end
|
25
25
|
|
26
|
-
def syntax
|
27
|
-
|
26
|
+
def syntax
|
27
|
+
r = [
|
28
28
|
comments_start,
|
29
29
|
syn_libname,
|
30
30
|
syn_filename,
|
@@ -36,271 +36,270 @@ def syntax
|
|
36
36
|
syn_fmt_big_nums,
|
37
37
|
syn_run,
|
38
38
|
comments_end,
|
39
|
-
|
40
|
-
|
41
|
-
end
|
39
|
+
]
|
40
|
+
r.flatten!
|
41
|
+
end
|
42
42
|
|
43
|
-
def comments_start
|
44
|
-
|
45
|
-
end
|
43
|
+
def comments_start
|
44
|
+
convert_to_comments(super)
|
45
|
+
end
|
46
46
|
|
47
|
-
def comments_end
|
48
|
-
|
49
|
-
end
|
47
|
+
def comments_end
|
48
|
+
convert_to_comments(super)
|
49
|
+
end
|
50
50
|
|
51
|
-
def convert_to_comments
|
52
|
-
|
53
|
-
|
51
|
+
def convert_to_comments(lines)
|
52
|
+
return [] if lines.empty?
|
53
|
+
[
|
54
54
|
'/*',
|
55
55
|
lines.map { |ln| ' ' + ln },
|
56
56
|
'*/',
|
57
57
|
blank,
|
58
|
-
|
59
|
-
end
|
58
|
+
].flatten
|
59
|
+
end
|
60
60
|
|
61
|
-
def syn_libname
|
62
|
-
|
63
|
-
end
|
61
|
+
def syn_libname
|
62
|
+
'libname ' + @sas_library_handle + ' ' + q(@sfc.data_dir_name) + @cmd_end
|
63
|
+
end
|
64
64
|
|
65
|
-
def syn_filename
|
66
|
-
|
67
|
-
end
|
65
|
+
def syn_filename
|
66
|
+
'filename ' + @sas_file_handle + ' ' + q(@sfc.data_file_name) + @cmd_end
|
67
|
+
end
|
68
68
|
|
69
|
-
def syn_val_labs
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
def syn_val_labs
|
70
|
+
var_list = @sfc.get_vars_with_values
|
71
|
+
return [] if var_list.empty?
|
72
|
+
r = [
|
73
73
|
syn_proc_format,
|
74
74
|
blank,
|
75
75
|
syn_val_labs_for_var_list(var_list),
|
76
76
|
syn_run,
|
77
|
-
|
78
|
-
|
79
|
-
end
|
77
|
+
]
|
78
|
+
r.flatten!
|
79
|
+
end
|
80
80
|
|
81
|
-
def syn_proc_format
|
82
|
-
|
83
|
-
end
|
81
|
+
def syn_proc_format
|
82
|
+
'proc format cntlout = ' + @sas_data_file_name + @sas_fmt_suffix + @cmd_end
|
83
|
+
end
|
84
84
|
|
85
|
-
def syn_val_labs_for_var_list
|
86
|
-
|
87
|
-
|
85
|
+
def syn_val_labs_for_var_list(var_list)
|
86
|
+
r = []
|
87
|
+
var_list.each do |var|
|
88
88
|
r.push syn_val_labs_for_var_start(var)
|
89
89
|
r.push syn_val_labs_for_var(var)
|
90
90
|
r.push syntax_end
|
91
|
+
end
|
92
|
+
r.flatten!
|
91
93
|
end
|
92
|
-
r.flatten!
|
93
|
-
end
|
94
94
|
|
95
|
-
def syn_val_labs_for_var_start
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
95
|
+
def syn_val_labs_for_var_start(var)
|
96
|
+
'value' +
|
97
|
+
(var.is_string_var ? ' $ ' : ' ') +
|
98
|
+
var.name +
|
99
|
+
@sas_fmt_suffix
|
100
|
+
end
|
101
101
|
|
102
|
-
def syn_val_labs_for_var
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
102
|
+
def syn_val_labs_for_var(var)
|
103
|
+
val_list = labelable_values(var)
|
104
|
+
return [] if val_list.empty?
|
105
|
+
m = max_value_length(var, val_list)
|
106
|
+
m = m + 2 if var.is_string_var
|
107
|
+
m = @segment_max_leng + 2 if m > @segment_max_leng + 2
|
108
|
+
fmt = " %-#{m}s %s %s"
|
109
|
+
r = val_list.collect { |val| syn_val_lab_for_val(var, val, fmt) }
|
110
|
+
r.flatten!
|
111
|
+
end
|
112
112
|
|
113
|
-
def syn_val_lab_for_val
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
113
|
+
def syn_val_lab_for_val(var, val, fmt)
|
114
|
+
lab = label_trunc(val.label, @label_max_leng)
|
115
|
+
lab = val.value if lab.nil? || (lab.strip.length == 0)
|
116
|
+
vs = val_as_s(var, val.value)
|
117
|
+
val_segments = label_segments(vs, @segment_max_leng).map { |s| val_q(var, s) }
|
118
|
+
lab_segments = label_segments(lab, @segment_max_leng).map { |s| q(s) }
|
119
|
+
weave_label_segments(fmt, val_segments, lab_segments, '=', ' ')
|
120
|
+
end
|
121
121
|
|
122
|
-
def syn_run
|
123
|
-
|
124
|
-
end
|
122
|
+
def syn_run
|
123
|
+
['run' + @cmd_end, blank]
|
124
|
+
end
|
125
125
|
|
126
|
-
def syn_df
|
127
|
-
|
126
|
+
def syn_df
|
127
|
+
r = [
|
128
128
|
syn_df_start,
|
129
129
|
syn_df_infile,
|
130
130
|
blank,
|
131
131
|
@sfc.data_structure == 'hier' ? syn_dfh : syn_dfr,
|
132
|
-
|
133
|
-
|
134
|
-
end
|
132
|
+
]
|
133
|
+
r.flatten!
|
134
|
+
end
|
135
135
|
|
136
|
-
def syn_df_start
|
137
|
-
|
138
|
-
end
|
136
|
+
def syn_df_start
|
137
|
+
'data ' + @sas_data_file_name + @cmd_end
|
138
|
+
end
|
139
139
|
|
140
|
-
def syn_df_infile
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
end
|
140
|
+
def syn_df_infile
|
141
|
+
# The LRECL specification is needed because the default behavior on some
|
142
|
+
# operating systems is to truncate records to 256 columns.
|
143
|
+
c = @sfc.last_column_used
|
144
|
+
'infile ' + @sas_file_handle + ' pad missover lrecl=' + c.to_s + @cmd_end
|
145
|
+
end
|
146
146
|
|
147
|
-
def syn_dfr
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
end
|
147
|
+
def syn_dfr
|
148
|
+
r = syn_input(@sfc.variables)
|
149
|
+
r.push blank
|
150
|
+
r
|
151
|
+
end
|
152
152
|
|
153
|
-
def syn_input
|
154
|
-
|
153
|
+
def syn_input(var_list)
|
154
|
+
r = [
|
155
155
|
'input',
|
156
156
|
syn_var_locations(var_list),
|
157
157
|
@cmd_end,
|
158
|
-
|
159
|
-
|
160
|
-
end
|
158
|
+
]
|
159
|
+
r.flatten!
|
160
|
+
end
|
161
161
|
|
162
|
-
def syn_var_locations
|
163
|
-
|
164
|
-
sprintf(
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
end
|
162
|
+
def syn_var_locations(var_list)
|
163
|
+
var_list.collect { |v|
|
164
|
+
sprintf(@var_loc_format, v.name) +
|
165
|
+
(v.is_string_var ? '$ ' : ' ') +
|
166
|
+
v.column_locations_as_s +
|
167
|
+
implied_decimal_fmt(v)
|
168
|
+
}
|
169
|
+
end
|
170
170
|
|
171
|
-
def syn_dfh
|
172
|
-
|
171
|
+
def syn_dfh
|
172
|
+
r = [
|
173
173
|
syn_dfh_retain,
|
174
174
|
syn_dfh_rec_type_block,
|
175
175
|
blank,
|
176
176
|
syn_dfh_if_blocks,
|
177
|
-
|
178
|
-
|
179
|
-
end
|
177
|
+
]
|
178
|
+
r.flatten!
|
179
|
+
end
|
180
180
|
|
181
|
-
def syn_dfh_retain
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
181
|
+
def syn_dfh_retain
|
182
|
+
return [] unless @sfc.rectangularize
|
183
|
+
var_list = non_last_non_common_vars
|
184
|
+
return [] if var_list.size == 0
|
185
|
+
r = [
|
186
186
|
'retain',
|
187
187
|
var_list.map { |var| ' ' + var.name },
|
188
188
|
syntax_end,
|
189
|
-
|
190
|
-
|
191
|
-
end
|
189
|
+
]
|
190
|
+
r.flatten!
|
191
|
+
end
|
192
192
|
|
193
|
-
def syn_dfh_rec_type_block
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
end
|
193
|
+
def syn_dfh_rec_type_block
|
194
|
+
r = syn_input([@sfc.record_type_var])
|
195
|
+
r[1] = r[1] + ' @'
|
196
|
+
r
|
197
|
+
end
|
198
198
|
|
199
|
-
def syn_dfh_if_blocks
|
200
|
-
|
201
|
-
|
202
|
-
|
199
|
+
def syn_dfh_if_blocks
|
200
|
+
if_cmd = 'if'
|
201
|
+
r = []
|
202
|
+
@sfc.record_types.each do |rt|
|
203
203
|
r.push(
|
204
|
-
|
205
|
-
|
206
|
-
|
204
|
+
syn_dfh_if_start(if_cmd, rt),
|
205
|
+
syn_input(@sfc.get_vars_by_record_type(rt)),
|
206
|
+
syn_dfh_if_end(rt)
|
207
207
|
)
|
208
208
|
if_cmd = 'else if'
|
209
|
+
end
|
210
|
+
r.flatten!
|
209
211
|
end
|
210
|
-
r.flatten!
|
211
|
-
end
|
212
212
|
|
213
|
-
def syn_dfh_if_start
|
214
|
-
|
215
|
-
|
213
|
+
def syn_dfh_if_start(if_cmd, rt)
|
214
|
+
rt_var = @sfc.record_type_var
|
215
|
+
r = [
|
216
216
|
if_cmd,
|
217
217
|
@sfc.record_type_var.name,
|
218
218
|
'=',
|
219
219
|
val_q(rt_var, val_as_s(rt_var, rt)),
|
220
220
|
'then do' + @cmd_end,
|
221
|
-
|
222
|
-
|
223
|
-
end
|
221
|
+
]
|
222
|
+
r.join(' ')
|
223
|
+
end
|
224
224
|
|
225
|
-
def syn_dfh_if_end
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
end
|
225
|
+
def syn_dfh_if_end(rt)
|
226
|
+
r = []
|
227
|
+
r.push 'output' + @cmd_end if (not @sfc.rectangularize) or @sfc.is_last_record_type(rt)
|
228
|
+
r.push 'end' + @cmd_end
|
229
|
+
r.push blank
|
230
|
+
r
|
231
|
+
end
|
232
232
|
|
233
|
-
def syn_var_labs
|
234
|
-
|
235
|
-
|
236
|
-
|
233
|
+
def syn_var_labs
|
234
|
+
var_list = @sfc.get_vars_with_var_labels
|
235
|
+
return [] if var_list.empty?
|
236
|
+
r = [
|
237
237
|
'label',
|
238
238
|
var_list.map { |var| syn_var_lab_for_var(var) },
|
239
239
|
syntax_end,
|
240
|
-
|
241
|
-
|
242
|
-
end
|
240
|
+
]
|
241
|
+
r.flatten!
|
242
|
+
end
|
243
243
|
|
244
|
-
def syn_var_lab_for_var
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
end
|
244
|
+
def syn_var_lab_for_var(var)
|
245
|
+
lab = label_trunc(var.label, @label_max_leng)
|
246
|
+
lab_segments = label_segments(lab, @segment_max_leng).map { |s| q(s) }
|
247
|
+
weave_label_segments(@var_lab_format, [var.name], lab_segments, '=', ' ')
|
248
|
+
end
|
249
249
|
|
250
|
-
def syn_fmt_big_nums
|
251
|
-
|
252
|
-
|
253
|
-
|
250
|
+
def syn_fmt_big_nums
|
251
|
+
big_num_vars = @sfc.get_big_nums
|
252
|
+
return [] if big_num_vars.empty?
|
253
|
+
r = [
|
254
254
|
'format',
|
255
255
|
syn_fmt_big_nums_for_var_list(big_num_vars),
|
256
256
|
syntax_end,
|
257
|
-
|
258
|
-
|
259
|
-
end
|
260
|
-
|
261
|
-
def syn_fmt_big_nums_for_var_list (var_list)
|
262
|
-
var_list.map do |v|
|
263
|
-
if v.implied_decimals > 0
|
264
|
-
sprintf @bignum_dec_format, v.name, v.width + 1, v.implied_decimals
|
265
|
-
else
|
266
|
-
sprintf @bignum_int_format, v.name, v.width
|
257
|
+
]
|
258
|
+
r.flatten!
|
267
259
|
end
|
268
|
-
end
|
269
|
-
end
|
270
260
|
|
261
|
+
def syn_fmt_big_nums_for_var_list(var_list)
|
262
|
+
var_list.map do |v|
|
263
|
+
if v.implied_decimals > 0
|
264
|
+
sprintf @bignum_dec_format, v.name, v.width + 1, v.implied_decimals
|
265
|
+
else
|
266
|
+
sprintf @bignum_int_format, v.name, v.width
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
271
270
|
|
272
|
-
def syn_fmt_link
|
273
|
-
|
274
|
-
|
275
|
-
|
271
|
+
def syn_fmt_link
|
272
|
+
var_list = @sfc.get_vars_with_values
|
273
|
+
return [] if var_list.empty?
|
274
|
+
r = [
|
276
275
|
'format',
|
277
276
|
syn_fmt_link_for_var_list(var_list),
|
278
277
|
syntax_end,
|
279
|
-
|
280
|
-
|
281
|
-
end
|
278
|
+
]
|
279
|
+
r.flatten!
|
280
|
+
end
|
282
281
|
|
283
|
-
def syn_fmt_link_for_var_list
|
284
|
-
|
282
|
+
def syn_fmt_link_for_var_list(var_list)
|
283
|
+
var_list.map { |v|
|
285
284
|
sprintf @fmt_link_format, v.name, v.name + @sas_fmt_suffix
|
286
|
-
|
287
|
-
end
|
285
|
+
}
|
286
|
+
end
|
288
287
|
|
289
|
-
def implied_decimal_fmt
|
290
|
-
|
291
|
-
|
292
|
-
end
|
288
|
+
def implied_decimal_fmt(var)
|
289
|
+
return '' if var.is_string_var or var.implied_decimals == 0
|
290
|
+
return ' .' + var.implied_decimals.to_s
|
291
|
+
end
|
293
292
|
|
294
|
-
def non_last_non_common_vars
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
293
|
+
def non_last_non_common_vars
|
294
|
+
# Returns a list of variables, excluding:
|
295
|
+
# - variables from the last record type
|
296
|
+
# - common variables
|
297
|
+
var_list = @sfc.rec_types_except_last.map do |rt|
|
299
298
|
vars = @sfc.get_vars_by_record_type(rt)
|
300
299
|
vars.find_all { |var| not var.is_common_var }
|
300
|
+
end
|
301
|
+
var_list.flatten!
|
301
302
|
end
|
302
|
-
var_list.flatten!
|
303
|
-
end
|
304
303
|
|
305
|
-
end
|
304
|
+
end
|
306
305
|
end
|