stats_package_syntax_file_generator 1.1.3 → 1.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/syntax_file/controller.rb +221 -213
- data/lib/syntax_file/maker.rb +96 -91
- data/lib/syntax_file/maker_rddi.rb +55 -55
- data/lib/syntax_file/maker_sas.rb +205 -204
- data/lib/syntax_file/maker_spss.rb +144 -143
- data/lib/syntax_file/maker_stata.rb +211 -211
- data/lib/syntax_file/maker_sts.rb +120 -120
- data/lib/syntax_file/value.rb +16 -15
- data/lib/syntax_file/variable.rb +41 -40
- data/tests/setup.rb +8 -8
- data/tests/tc_maker.rb +1 -1
- data/tests/tc_maker_stata.rb +1 -1
- metadata +13 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d70e7b804a5ab33d5c760f9bdf3e78952698635f52696434090e0e9b253a940a
|
4
|
+
data.tar.gz: f34831874237c55bba2be89b67ad6c474ebf10d6c30198f11d514db97b3761e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7681d6c9dad0c9b13fb6a7111b40e1812d1f1498d542f14b602d8e32cda3ed0255f53b9186bc2fe842aa13937c149963a1a3a25782652f616eda83707489f182
|
7
|
+
data.tar.gz: 0f6a2791585490994d5c199a7664cf8210f9b4872bbbb788755d5485625b77f3e3e51aaa38eb84c861aeab4d4a81fee759f41679a00e47f1d3fd276fb0a75a62
|
@@ -4,276 +4,284 @@
|
|
4
4
|
# https://github.com/mnpopcenter/stats_package_syntax_file_generator
|
5
5
|
|
6
6
|
module SyntaxFile
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
7
|
+
class Controller
|
8
|
+
|
9
|
+
VERSION = "1.1.6"
|
10
|
+
|
11
|
+
ATTR = {
|
12
|
+
:project => { :req => false, :rw => 'rw', :def => '', :yaml => true },
|
13
|
+
:caller => { :req => false, :rw => 'rw', :def => '', :yaml => true },
|
14
|
+
:data_dir_name => { :req => false, :rw => 'rw', :def => '.', :yaml => true },
|
15
|
+
:data_file_name => { :req => false, :rw => 'rw', :def => 'DATA_FILE', :yaml => true },
|
16
|
+
:output_formats => { :req => false, :rw => 'rw', :def => nil, :yaml => true },
|
17
|
+
:output_dir_name => { :req => false, :rw => 'rw', :def => '.', :yaml => true },
|
18
|
+
:output_file_stem => { :req => false, :rw => 'rw', :def => '%s', :yaml => true },
|
19
|
+
:output_file_ext => { :req => false, :rw => 'rw', :def => nil, :yaml => true },
|
20
|
+
:output_overwrite => { :req => false, :rw => 'rw', :def => false, :yaml => true },
|
21
|
+
:data_structure => { :req => false, :rw => 'rw', :def => 'rect', :yaml => true },
|
22
|
+
:record_types => { :req => false, :rw => 'rw', :def => nil, :yaml => true },
|
23
|
+
:record_type_var_name => { :req => false, :rw => 'rw', :def => '', :yaml => true },
|
24
|
+
:rectangularize => { :req => false, :rw => 'rw', :def => false, :yaml => true },
|
25
|
+
:all_vars_as_string => { :req => false, :rw => 'rw', :def => false, :yaml => true },
|
26
|
+
:select_vars_by_record_type => { :req => false, :rw => 'rw', :def => false, :yaml => true },
|
27
|
+
:variables => { :req => false, :rw => 'r', :def => nil, :yaml => false },
|
28
|
+
:yaml_files => { :req => false, :rw => 'r', :def => nil, :yaml => false },
|
29
|
+
:output_encoding => { :req => false, :rw => 'r', :def => "iso-8859-1",:yaml => true },
|
30
|
+
}
|
31
|
+
|
32
|
+
ATTR.each_key do |k|
|
33
|
+
attr_reader k if ATTR[k][:rw].include? 'r'
|
34
|
+
attr_writer k if ATTR[k][:rw].include? 'w'
|
35
|
+
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
raise(ArgumentError, "Missing required parameter: '#{k}'.") if
|
37
|
+
def initialize (args = {})
|
38
|
+
ATTR.each_key { |k|
|
39
|
+
raise(ArgumentError, "Missing required parameter: '#{k}'.") if
|
40
|
+
ATTR[k][:req] and not args.has_key?(k)
|
40
41
|
v = args.has_key?(k) ? args[k] : ATTR[k][:def]
|
41
42
|
instance_variable_set("@#{k}".to_sym, v)
|
42
|
-
|
43
|
+
}
|
43
44
|
|
44
|
-
|
45
|
-
'sas'
|
46
|
-
'spss'
|
45
|
+
@output_file_ext = {
|
46
|
+
'sas' => '.sas',
|
47
|
+
'spss' => '.sps',
|
47
48
|
'stata' => '.do',
|
48
|
-
'sts'
|
49
|
-
'rddi'
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
'sts' => '.sts',
|
50
|
+
'rddi' => '.R'
|
51
|
+
} if @output_file_ext.nil?
|
52
|
+
@output_formats = [] if @output_formats.nil?
|
53
|
+
@record_types = [] if @record_types.nil?
|
54
|
+
@variables = [] if @variables.nil?
|
55
|
+
@yaml_files = [] if @yaml_files.nil?
|
56
|
+
read_metadata_from_yaml
|
57
|
+
end
|
57
58
|
|
58
|
-
# Methods to import metadata from YAML files into the Controller object.
|
59
59
|
|
60
|
-
|
61
|
-
# Caller can supply a file name or an array of file names.
|
62
|
-
@yaml_files = file_names.to_a
|
63
|
-
read_metadata_from_yaml
|
64
|
-
end
|
60
|
+
# Methods to import metadata from YAML files into the Controller object.
|
65
61
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
62
|
+
def yaml_files= (file_names)
|
63
|
+
# Caller can supply a file name or an array of file names.
|
64
|
+
@yaml_files = file_names.to_a
|
65
|
+
read_metadata_from_yaml
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_metadata_from_yaml
|
69
|
+
return if @yaml_files.empty?
|
70
|
+
md = {}
|
71
|
+
@yaml_files.each { |f| md.merge! YAML.load_file(f) }
|
72
|
+
md = symbolize_keys(md)
|
73
|
+
load_yaml_md(md)
|
74
|
+
end
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
-
|
76
|
+
def load_yaml_md (md)
|
77
|
+
# Uses metadata from yaml to set metadata-related instance variables.
|
78
|
+
ATTR.each_key do |k|
|
77
79
|
next unless md.has_key?(k) and ATTR[k][:yaml]
|
78
80
|
instance_variable_set("@#{k}".to_sym, md[k])
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
end
|
82
|
+
return unless md.has_key?(:variables)
|
83
|
+
@variables = []
|
84
|
+
return unless md[:variables].size > 0
|
85
|
+
md[:variables].each do |md_var|
|
84
86
|
vals = md_var.delete(:values)
|
85
87
|
var = add_variable(md_var)
|
86
88
|
vals.each { |v| var.add_value(v) } unless vals.nil?
|
87
|
-
end
|
88
89
|
end
|
90
|
+
end
|
89
91
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
h.inject({}) { |return_hash,
|
94
|
-
|
92
|
+
def symbolize_keys (h)
|
93
|
+
# Recursively converts hash keys from strings to symbols.
|
94
|
+
if h.instance_of? Hash
|
95
|
+
h.inject({}) { |return_hash,(k,v)| return_hash[k.to_sym] = symbolize_keys(v); return_hash }
|
96
|
+
elsif h.instance_of? Array
|
95
97
|
h.map { |v| symbolize_keys(v) }
|
96
|
-
|
98
|
+
else
|
97
99
|
h
|
98
|
-
end
|
99
100
|
end
|
101
|
+
end
|
100
102
|
|
101
|
-
|
103
|
+
# Methods to add or get variables.
|
102
104
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
def add_variable (args)
|
106
|
+
@variables.push Variable.new(args)
|
107
|
+
@variables[-1]
|
108
|
+
end
|
107
109
|
|
108
|
-
|
109
|
-
|
110
|
-
|
110
|
+
def clear_variables
|
111
|
+
@variables = []
|
112
|
+
end
|
111
113
|
|
112
|
-
|
113
|
-
|
114
|
-
|
114
|
+
def get_var_by_name (n)
|
115
|
+
@variables.find { |v| v.name == n }
|
116
|
+
end
|
115
117
|
|
116
|
-
|
117
|
-
|
118
|
-
|
118
|
+
def get_vars_by_record_type (rt)
|
119
|
+
@variables.find_all { |v| v.record_type == rt or v.is_common_var }
|
120
|
+
end
|
119
121
|
|
120
|
-
|
121
|
-
|
122
|
-
|
122
|
+
def get_vars_with_var_labels
|
123
|
+
@variables.find_all { |v| v.label.length > 0 }
|
124
|
+
end
|
123
125
|
|
124
|
-
|
125
|
-
|
126
|
+
def get_vars_with_values
|
127
|
+
@variables.find_all { |var|
|
126
128
|
var.values.size > 0 and
|
127
|
-
|
128
|
-
|
129
|
-
|
129
|
+
not var.suppress_labels
|
130
|
+
}
|
131
|
+
end
|
130
132
|
|
131
|
-
|
132
|
-
|
133
|
+
def get_big_nums
|
134
|
+
@variables.find_all { |var|
|
133
135
|
var.width > 8 and
|
134
|
-
|
135
|
-
|
136
|
-
|
136
|
+
not var.is_string_var
|
137
|
+
}
|
138
|
+
end
|
137
139
|
|
138
|
-
def record_type_var
|
139
|
-
get_var_by_name(@record_type_var_name)
|
140
|
-
end
|
141
140
|
|
142
|
-
|
141
|
+
def record_type_var
|
142
|
+
get_var_by_name(@record_type_var_name)
|
143
|
+
end
|
143
144
|
|
144
|
-
def add_value(args)
|
145
|
-
@variables[-1].values.push Value.new(args)
|
146
|
-
@variables[-1].values[-1]
|
147
|
-
end
|
148
145
|
|
149
|
-
|
150
|
-
vals.flatten!
|
151
|
-
vals.map { |v| Value.new(v) }
|
152
|
-
end
|
146
|
+
# Methods for adding values to variables.
|
153
147
|
|
154
|
-
|
148
|
+
def add_value (args)
|
149
|
+
@variables[-1].values.push Value.new(args)
|
150
|
+
@variables[-1].values[-1]
|
151
|
+
end
|
155
152
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
153
|
+
def new_values (*vals)
|
154
|
+
vals.flatten!
|
155
|
+
vals.map { |v| Value.new(v) }
|
156
|
+
end
|
160
157
|
|
161
|
-
def rec_types_except_last
|
162
|
-
r = Array.new(@record_types)
|
163
|
-
r.pop
|
164
|
-
r
|
165
|
-
end
|
166
158
|
|
167
|
-
|
159
|
+
# Methods for record types.
|
168
160
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
161
|
+
def is_last_record_type (rt)
|
162
|
+
return true if @record_types.size > 0 and @record_types[-1] == rt
|
163
|
+
return false
|
164
|
+
end
|
173
165
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
166
|
+
def rec_types_except_last
|
167
|
+
r = Array.new(@record_types)
|
168
|
+
r.pop
|
169
|
+
r
|
170
|
+
end
|
178
171
|
|
179
|
-
def data_file_name_stem
|
180
|
-
File.basename(@data_file_name, '.*')
|
181
|
-
end
|
182
172
|
|
183
|
-
|
184
|
-
Hash[* @record_types.map { |rt| [rt, 0] }.flatten]
|
185
|
-
end
|
173
|
+
# Helper methods.
|
186
174
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
175
|
+
def max_var_name_length
|
176
|
+
return 0 if @variables.empty?
|
177
|
+
@variables.map { |v| v.name.length }.max
|
178
|
+
end
|
179
|
+
|
180
|
+
def max_col_loc_width
|
181
|
+
return 0 if @variables.empty?
|
182
|
+
@variables.map { |v| v.end_column.to_s.length }.max
|
183
|
+
end
|
191
184
|
|
192
|
-
|
185
|
+
def data_file_name_stem
|
186
|
+
File.basename(@data_file_name, '.*')
|
187
|
+
end
|
193
188
|
|
194
|
-
|
195
|
-
|
196
|
-
|
189
|
+
def rec_type_lookup_hash
|
190
|
+
Hash[ * @record_types.map { |rt| [rt, 0] }.flatten ]
|
191
|
+
end
|
197
192
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
193
|
+
def last_column_used
|
194
|
+
return 0 if @variables.empty?
|
195
|
+
@variables.map { |v| v.end_column }.max
|
196
|
+
end
|
197
|
+
|
198
|
+
# Output methods.
|
202
199
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
200
|
+
def to_s
|
201
|
+
YAML.dump(self)
|
202
|
+
end
|
203
|
+
|
204
|
+
def generate_syntax_files
|
205
|
+
bad_metadata('no output formats')if @output_formats.empty?
|
206
|
+
@output_formats.each { |t| generate_syntax_file(t) }
|
207
|
+
end
|
208
|
+
|
209
|
+
def generate_syntax_file (syntax_type)
|
210
|
+
msg = "output directory does not exist => #{@output_dir_name}"
|
211
|
+
bad_metadata(msg) unless File.directory?(@output_dir_name)
|
212
|
+
file_name = File.join(
|
207
213
|
@output_dir_name,
|
208
214
|
sprintf(@output_file_stem, data_file_name_stem) + @output_file_ext[syntax_type]
|
209
|
-
|
210
|
-
|
215
|
+
)
|
216
|
+
if File.file?(file_name) and not @output_overwrite
|
211
217
|
$stderr.puts "Skipping file that aready exists => #{file_name}."
|
212
|
-
|
218
|
+
else
|
213
219
|
if RUBY_VERSION.start_with? "1.8"
|
214
220
|
File.open(file_name, 'w') { |f| f.puts syntax(syntax_type) }
|
215
221
|
else
|
216
222
|
File.open(file_name, "w:#{self.output_encoding}") { |f|
|
217
223
|
|
218
|
-
|
219
|
-
|
224
|
+
lines = syntax(syntax_type)
|
225
|
+
lines.each do |line|
|
220
226
|
begin
|
221
|
-
|
222
|
-
rescue Exception
|
223
|
-
|
227
|
+
f.puts line.rstrip.encode(self.output_encoding, line.encoding.to_s,{:invalid=>:replace, :undef=>:replace,:replace => '?'})
|
228
|
+
rescue Exception=>msg
|
229
|
+
puts "Failed encoding on line #{line} #{msg}"
|
224
230
|
end
|
225
|
-
|
231
|
+
end
|
226
232
|
}
|
227
233
|
end
|
228
234
|
|
229
|
-
end
|
230
235
|
end
|
236
|
+
end
|
231
237
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
238
|
+
def syntax (syntax_type)
|
239
|
+
validate_metadata(:minimal => true)
|
240
|
+
modify_metadata
|
241
|
+
validate_metadata
|
242
|
+
|
243
|
+
maker_class = 'Maker' + syntax_type.upcase
|
244
|
+
syntax_maker = eval(maker_class).new(self, syntax_type)
|
245
|
+
syntax_maker.syntax
|
246
|
+
end
|
236
247
|
|
237
|
-
maker_class = 'Maker' + syntax_type.upcase
|
238
|
-
syntax_maker = eval(maker_class).new(self, syntax_type)
|
239
|
-
syntax_maker.syntax
|
240
|
-
end
|
241
248
|
|
242
|
-
|
243
|
-
|
249
|
+
# Before generating syntax, we need to handle some controller-level
|
250
|
+
# options that require global modification of the metadata.
|
244
251
|
|
245
|
-
|
246
|
-
|
247
|
-
|
252
|
+
def modify_metadata
|
253
|
+
# Force all variables to be strings.
|
254
|
+
if @all_vars_as_string
|
248
255
|
@variables.each do |var|
|
249
|
-
|
250
|
-
|
251
|
-
|
256
|
+
var.is_string_var = true
|
257
|
+
var.is_double_var = false
|
258
|
+
var.implied_decimals = 0
|
252
259
|
end
|
253
|
-
|
260
|
+
end
|
254
261
|
|
255
|
-
|
256
|
-
|
257
|
-
|
262
|
+
# If the user wants to rectangularize hierarchical data, the
|
263
|
+
# select_vars_by_record_type option is required.
|
264
|
+
@select_vars_by_record_type = true if @rectangularize
|
258
265
|
|
259
|
-
|
260
|
-
|
266
|
+
# Remove any variables not belonging to the declared record types.
|
267
|
+
if @select_vars_by_record_type
|
261
268
|
rt_lookup = rec_type_lookup_hash()
|
262
269
|
@variables = @variables.find_all { |var| var.is_common_var or rt_lookup[var.record_type] }
|
263
|
-
end
|
264
270
|
end
|
271
|
+
end
|
272
|
+
|
265
273
|
|
266
|
-
|
274
|
+
# Before generating syntax, run a sanity check on the metadata.
|
267
275
|
|
268
|
-
|
269
|
-
|
276
|
+
def validate_metadata (check = {})
|
277
|
+
bad_metadata('no variables') if @variables.empty?
|
270
278
|
|
271
|
-
|
279
|
+
if @rectangularize
|
272
280
|
msg = 'the rectangularize option requires data_structure=hier'
|
273
281
|
bad_metadata(msg) unless @data_structure == 'hier'
|
274
|
-
|
282
|
+
end
|
275
283
|
|
276
|
-
|
284
|
+
if @data_structure == 'hier' or @select_vars_by_record_type
|
277
285
|
bad_metadata('no record types') if @record_types.empty?
|
278
286
|
|
279
287
|
msg = 'record types must be unique'
|
@@ -284,34 +292,34 @@ module SyntaxFile
|
|
284
292
|
|
285
293
|
msg = 'with no common variables, every record type needs at least one variable ('
|
286
294
|
if @variables.find { |var| var.is_common_var }.nil?
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
295
|
+
@record_types.each do |rt|
|
296
|
+
next if get_vars_by_record_type(rt).size > 0
|
297
|
+
bad_metadata(msg + rt + ')')
|
298
|
+
end
|
291
299
|
end
|
292
|
-
|
300
|
+
end
|
293
301
|
|
294
|
-
|
302
|
+
if @data_structure == 'hier'
|
295
303
|
bad_metadata('no record type variable') if record_type_var.nil?
|
296
|
-
|
304
|
+
end
|
297
305
|
|
298
|
-
|
306
|
+
return if check[:minimal]
|
299
307
|
|
300
|
-
|
301
|
-
v.start_column
|
302
|
-
v.width
|
308
|
+
@variables.each do |v|
|
309
|
+
v.start_column = v.start_column.to_i
|
310
|
+
v.width = v.width.to_i
|
303
311
|
v.implied_decimals = v.implied_decimals.to_i
|
304
|
-
bad_metadata("#{v.name}, start_column") unless v.start_column
|
305
|
-
bad_metadata("#{v.name}, width") unless v.width
|
312
|
+
bad_metadata("#{v.name}, start_column" ) unless v.start_column > 0
|
313
|
+
bad_metadata("#{v.name}, width" ) unless v.width > 0
|
306
314
|
bad_metadata("#{v.name}, implied_decimals") unless v.implied_decimals >= 0
|
307
|
-
end
|
308
315
|
end
|
316
|
+
end
|
309
317
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
318
|
+
def bad_metadata (msg)
|
319
|
+
msg = 'Invalid metadata: ' + msg
|
320
|
+
abort(msg) if @caller == 'vb' or @caller == 'dcp'
|
321
|
+
raise(RuntimeError, msg)
|
322
|
+
end
|
315
323
|
|
316
|
-
|
324
|
+
end
|
317
325
|
end
|