rsmart_toolbox 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # RsmartToolbox
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'rsmart_toolbox'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install rsmart_toolbox
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/rsmart_toolbox/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ # rSmart client library and command-line tool to help interact with rSmart's cloud APIs.
2
+ # Copyright (C) 2014 The rSmart Group, Inc.
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require "bundler/gem_tasks"
18
+ require "rspec/core/rake_task"
19
+
20
+ task :default => [:spec]
21
+ task :test => [:spec]
22
+
23
+ desc "Run the specs."
24
+ RSpec::Core::RakeTask.new do |t|
25
+ t.pattern = "spec/**/*_spec.rb"
26
+ end
@@ -0,0 +1,23 @@
1
+ # rSmart client library and command-line tool to help interact with rSmart's cloud APIs.
2
+ # Copyright (C) 2014 The rSmart Group, Inc.
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'csv'
18
+ require 'optparse'
19
+ require 'pp'
20
+ require "rsmart_toolbox/version"
21
+
22
+ module RsmartToolbox
23
+ end
@@ -0,0 +1,240 @@
1
+ # rSmart client library and command-line tool to help interact with rSmart's cloud APIs.
2
+ # Copyright (C) 2014 The rSmart Group, Inc.
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require "rsmart_toolbox"
18
+
19
+ module RsmartToolbox::ETL
20
+
21
+ class TextParseError < StandardError
22
+ end
23
+
24
+ # Responds to String or Exception.
25
+ def self.error(e)
26
+ if e.kind_of? String
27
+ # default to TextParseError
28
+ return TextParseError.new "ERROR: Line #{$INPUT_LINE_NUMBER}: #{e}"
29
+ end
30
+ if e.kind_of? Exception
31
+ return e.exception "ERROR: Line #{$INPUT_LINE_NUMBER}: #{e}"
32
+ end
33
+ raise ArgumentError, "Unsupported error type: #{e.class}"
34
+ end
35
+
36
+ # Responds to String or Exception.
37
+ def self.warning(e)
38
+ if e.kind_of? String
39
+ # default to TextParseError
40
+ return TextParseError.new "WARN: Line #{$INPUT_LINE_NUMBER}: #{e}"
41
+ end
42
+ if e.kind_of? Exception
43
+ return e.exception "WARN: Line #{$INPUT_LINE_NUMBER}: #{e}"
44
+ end
45
+ raise ArgumentError, "Unsupported error type: #{e.class}"
46
+ end
47
+
48
+ # Test to see if subject is a member of valid_values Array
49
+ def self.valid_value(subject, valid_values, opt={})
50
+ raise ArgumentError, "valid_values must not be nil!" if valid_values.nil?
51
+ if valid_values.kind_of? Regexp
52
+ return true if subject =~ valid_values
53
+ end
54
+ if valid_values.kind_of? Array
55
+ raise ArgumentError, "valid_values must have at least one element!" unless valid_values.length > 0
56
+ if opt[:case_sensitive] == false # case insensitive comparison requested
57
+ raise ArgumentError, "case_sensitive only supported for Strings!" unless subject.kind_of?(String)
58
+ valid_values.each do |valid_value|
59
+ return true if valid_value.casecmp(subject) == 0
60
+ end
61
+ end
62
+ return true if valid_values.include? subject # default to == equality
63
+ end
64
+ return false
65
+ end
66
+
67
+ def self.parse_boolean(str, opt={})
68
+ return true if str == true
69
+ return false if str == false
70
+ b = parse_string str, opt
71
+ return true if b =~ /^(active|a|true|t|yes|y|1)$/i
72
+ return false if b =~ /^(inactive|i|false|f|no|n|0)$/i
73
+ if b.empty? && !opt[:default].nil?
74
+ return opt[:default]
75
+ end
76
+ if b.empty?
77
+ return nil
78
+ end
79
+ raise RsmartToolbox::ETL::error TextParseError.new "invalid value for Boolean: '#{str}'"
80
+ end
81
+
82
+ # Simply here to help ensure we consistently apply the same encoding options.
83
+ def self.encode(str, opt={} )
84
+ opt[:encoding] = "UTF-8" if opt[:encoding].nil?
85
+ str.encode( opt[:encoding], :invalid => :replace,
86
+ :undef => :replace, :replace => "" )
87
+ end
88
+
89
+ # Matches MRI CSV specification:
90
+ # The header String is downcased, spaces are replaced with underscores,
91
+ # non-word characters are dropped, and finally to_sym() is called.
92
+ def self.to_symbol(str)
93
+ raise ArgumentError, "Illegal symbol name: '#{str}'" if str.nil? || str.empty?
94
+ encode( str.downcase.gsub(/\s+/, "_").gsub(/\W+/, "") ).to_sym
95
+ end
96
+
97
+ # DRY up some common string manipulation
98
+ def self.mutate_sql_stmt!(insert_str, column_name, values_str, value)
99
+ insert_str.concat "#{column_name.upcase},"
100
+ # TODO what are all of the valid types that should not be quoted?
101
+ if value.kind_of? Integer
102
+ values_str.concat "#{value},"
103
+ else
104
+ values_str.concat "'#{value}',"
105
+ end
106
+ end
107
+
108
+ def self.escape_single_quotes(str)
109
+ if str.nil?
110
+ return nil
111
+ end
112
+ return str.to_s.gsub("'", "\\\\'")
113
+ end
114
+
115
+ def self.parse_string(str, opt={})
116
+ opt[:strict] = true if opt[:strict].nil?
117
+ retval = encode str.to_s.strip
118
+ if opt[:required] && retval.empty?
119
+ raise RsmartToolbox::ETL::error TextParseError.new "Required data element '#{opt[:name]}' not found: '#{str}'"
120
+ end
121
+ if opt[:default] && retval.empty?
122
+ retval = opt[:default]
123
+ end
124
+ if opt[:length] && retval.length > opt[:length].to_i
125
+ detail = "#{opt[:name]}.length > #{opt[:length]}: '#{str}'-->'#{str[0..(opt[:length] - 1)]}'"
126
+ if opt[:strict]
127
+ raise RsmartToolbox::ETL::error TextParseError.new "Data exceeds maximum field length: #{detail}"
128
+ end
129
+ RsmartToolbox::ETL::warning "Data will be truncated: #{detail}"
130
+ end
131
+ if opt[:valid_values] && ! valid_value(retval, opt[:valid_values], opt)
132
+ raise RsmartToolbox::ETL::error TextParseError.new "Illegal #{opt[:name]}: value '#{str}' not found in: #{opt[:valid_values]}"
133
+ end
134
+ return escape_single_quotes retval
135
+ end
136
+
137
+ def self.parse_string!(row, insert_str, values_str, opt={})
138
+ raise ArgumentError, "opt[:name] is required!" unless opt[:name]
139
+ str = parse_string( row[ to_symbol( opt[:name] ) ], opt )
140
+ mutate_sql_stmt! insert_str, opt[:name], values_str, str
141
+ end
142
+
143
+ def self.parse_integer(str, opt={})
144
+ s = parse_string str, opt
145
+ if s.empty?
146
+ return nil;
147
+ else
148
+ return s.to_i
149
+ end
150
+ end
151
+
152
+ def self.parse_integer!(row, insert_str, values_str, opt={})
153
+ raise ArgumentError, "opt[:name] is required!" unless opt[:name]
154
+ i = parse_integer( row[ to_symbol( opt[:name] ) ], opt )
155
+ mutate_sql_stmt! insert_str, opt[:name], values_str, i
156
+ end
157
+
158
+ def self.parse_float(str, opt={})
159
+ s = parse_string str, opt
160
+ if s.empty?
161
+ return nil;
162
+ else
163
+ return s.to_f
164
+ end
165
+ end
166
+
167
+ # Useful for parsing "flag" like values. Always returns upcase for consistency.
168
+ # Assumes :strict :length of 1 by default.
169
+ def self.parse_flag(str, opt={})
170
+ opt[:length] = 1 if opt[:length].nil?
171
+ opt[:upcase] = true if opt[:upcase].nil?
172
+ retval = parse_string str, opt
173
+ retval = retval.upcase if opt[:upcase] == true
174
+ return retval
175
+ end
176
+
177
+ # Designed specifically for actv_ind, but could be used on *any*
178
+ # fields that matches /^(Y|N)$/i.
179
+ def self.parse_actv_ind(str, opt={})
180
+ # `ACTV_IND` varchar(1) COLLATE utf8_bin DEFAULT 'Y',
181
+ opt[:name] = "actv_ind" if opt[:name].nil?
182
+ opt[:default] = "Y" if opt[:default].nil?
183
+ opt[:valid_values] = /^(Y|N)$/i if opt[:valid_values].nil?
184
+ return parse_flag str, opt
185
+ end
186
+
187
+ # Designed specifically for actv_ind, but could be used on *any*
188
+ # fields that matches /^(Y|N)$/i.
189
+ def self.parse_actv_ind!(row, insert_str, values_str, opt={})
190
+ # `ACTV_IND` varchar(1) COLLATE utf8_bin DEFAULT 'Y',
191
+ opt[:name] = "actv_ind" if opt[:name].nil?
192
+ actv_ind = RsmartToolbox::ETL::parse_actv_ind row[ to_symbol( opt[:name] ) ]
193
+ RsmartToolbox::ETL::mutate_sql_stmt! insert_str, opt[:name], values_str, actv_ind
194
+ end
195
+
196
+ # Parse common command line options for CSV --> SQL transformations.
197
+ def self.parse_csv_command_line_options(
198
+ executable, args, opt={ csv_options: { headers: :first_row,
199
+ header_converters: :symbol,
200
+ skip_blanks: true,
201
+ col_sep: ",", # comma by default
202
+ quote_char: '"', # double quote by default
203
+ }
204
+ } )
205
+ optparse = OptionParser.new do |opts|
206
+ opts.banner = "Usage: #{executable} [options] csv_file"
207
+ opts.on( '-o [sql_file_output]' ,'--output [sql_file_output]', 'The file the SQL data will be writen to... (defaults to <csv_file>.sql)') do |f|
208
+ opt[:sql_filename] = f
209
+ end
210
+ opts.on( '-s [separator_character]' ,'--separator [separator_character]', 'The character that separates each column of the CSV file.') do |s|
211
+ opt[:col_sep] = s
212
+ end
213
+ opts.on( '-q [quote_character]' ,'--quote [quote_character]', 'The character used to quote fields.') do |q|
214
+ opt[:quote_char] = q
215
+ end
216
+ opts.on( '-h', '--help', 'Display this screen' ) do
217
+ puts opts
218
+ exit 1
219
+ end
220
+
221
+ opt[:csv_filename] = args[0] unless opt[:csv_filename]
222
+ if opt[:csv_filename].nil? || opt[:csv_filename].empty?
223
+ puts opts
224
+ exit 1
225
+ end
226
+ end
227
+ optparse.parse!
228
+
229
+ # construct a sensible default ouptput filename
230
+ unless opt[:sql_filename]
231
+ file_extension = File.extname opt[:csv_filename]
232
+ dir_name = File.dirname opt[:csv_filename]
233
+ base_name = File.basename opt[:csv_filename], file_extension
234
+ opt[:sql_filename] = "#{dir_name}/#{base_name}.sql"
235
+ end
236
+
237
+ return opt
238
+ end
239
+
240
+ end
@@ -0,0 +1,190 @@
1
+ # rSmart client library and command-line tool to help interact with rSmart's cloud APIs.
2
+ # Copyright (C) 2014 The rSmart Group, Inc.
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require "rsmart_toolbox/etl"
18
+
19
+ module RsmartToolbox::ETL::GRM
20
+
21
+ def self.parse_rolodex_id!(row, insert_str, values_str, opt={})
22
+ # `ROLODEX_ID` decimal(6,0) NOT NULL DEFAULT '0',
23
+ opt[:name] = "ROLODEX_ID" if opt[:name].nil?
24
+ opt[:required] = true if opt[:required].nil?
25
+ opt[:length] = 6 if opt[:length].nil?
26
+ RsmartToolbox::ETL::parse_integer! row, insert_str, values_str, opt
27
+ end
28
+
29
+ def self.parse_country_code!(row, insert_str, values_str, opt={})
30
+ # `COUNTRY_CODE` char(3) COLLATE utf8_bin DEFAULT NULL,
31
+ opt[:name] = "COUNTRY_CODE" if opt[:name].nil?
32
+ opt[:length] = 3 if opt[:length].nil?
33
+ RsmartToolbox::ETL::parse_string! row, insert_str, values_str, opt
34
+ end
35
+
36
+ def self.parse_state!(row, insert_str, values_str, opt={})
37
+ # `STATE` varchar(30) COLLATE utf8_bin DEFAULT NULL,
38
+ opt[:name] = "STATE" if opt[:name].nil?
39
+ opt[:length] = 30 if opt[:length].nil?
40
+ RsmartToolbox::ETL::parse_string! row, insert_str, values_str, opt
41
+ end
42
+
43
+ def self.parse_sponsor_code!(row, insert_str, values_str, opt={})
44
+ # `SPONSOR_CODE` char(6) COLLATE utf8_bin NOT NULL DEFAULT '',
45
+ opt[:name] = "SPONSOR_CODE" if opt[:name].nil?
46
+ opt[:required] = true if opt[:required].nil?
47
+ opt[:length] = 6 if opt[:length].nil?
48
+ RsmartToolbox::ETL::parse_string! row, insert_str, values_str, opt
49
+ end
50
+
51
+ def self.parse_postal_code!(row, insert_str, values_str, opt={})
52
+ # `POSTAL_CODE` varchar(15) COLLATE utf8_bin DEFAULT NULL,
53
+ opt[:name] = "POSTAL_CODE" if opt[:name].nil?
54
+ opt[:length] = 15 if opt[:length].nil?
55
+ RsmartToolbox::ETL::parse_string! row, insert_str, values_str, opt
56
+ end
57
+
58
+ def self.parse_owned_by_unit!(row, insert_str, values_str, opt={})
59
+ # `OWNED_BY_UNIT` varchar(8) COLLATE utf8_bin NOT NULL,
60
+ opt[:name] = "OWNED_BY_UNIT" if opt[:name].nil?
61
+ opt[:required] = true if opt[:required].nil?
62
+ opt[:length] = 8 if opt[:length].nil?
63
+ RsmartToolbox::ETL::parse_string! row, insert_str, values_str, opt
64
+ end
65
+
66
+ def self.parse_email_address(str, opt={})
67
+ # `EMAIL_ADDRESS` varchar(60) COLLATE utf8_bin DEFAULT NULL,
68
+ opt[:name] = "EMAIL_ADDRESS" if opt[:name].nil?
69
+ opt[:length] = 60 if opt[:length].nil?
70
+ opt[:valid_values] = /^(([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?))?$/ if opt[:valid_values].nil?
71
+ return RsmartToolbox::ETL::parse_string str, opt
72
+ end
73
+
74
+ def self.parse_email_address!(row, insert_str, values_str, opt={})
75
+ # `EMAIL_ADDRESS` varchar(60) COLLATE utf8_bin DEFAULT NULL,
76
+ opt[:name] = "EMAIL_ADDRESS" if opt[:name].nil?
77
+ email_address = parse_email_address row[ RsmartToolbox::ETL::to_symbol( opt[:name] ) ]
78
+ RsmartToolbox::ETL::mutate_sql_stmt! insert_str, opt[:name], values_str, email_address
79
+ end
80
+
81
+ def self.parse_principal_id(str, opt={})
82
+ # `PRNCPL_ID` varchar(40) COLLATE utf8_bin NOT NULL DEFAULT '',
83
+ opt[:name] = "PRNCPL_ID" if opt[:name].nil?
84
+ opt[:required] = true if opt[:required].nil?
85
+ opt[:length] = 40 if opt[:length].nil?
86
+ RsmartToolbox::ETL::parse_string str, opt
87
+ end
88
+
89
+ def self.parse_principal_name(str, opt={})
90
+ # `PRNCPL_NM` varchar(100) COLLATE utf8_bin NOT NULL,
91
+ opt[:name] = "PRNCPL_NM" if opt[:name].nil?
92
+ opt[:length] = 100 if opt[:length].nil?
93
+ opt[:required] = true if opt[:required].nil?
94
+ prncpl_nm = RsmartToolbox::ETL::parse_string str, opt
95
+ unless prncpl_nm =~ /^([a-z0-9\@\.\_\-]+)$/
96
+ raise RsmartToolbox::ETL::error TextParseError.new "Illegal prncpl_nm found: '#{prncpl_nm}'"
97
+ end
98
+ return prncpl_nm
99
+ end
100
+
101
+ def self.parse_emp_stat_cd(str, opt={})
102
+ # `EMP_STAT_CD` varchar(40) COLLATE utf8_bin DEFAULT NULL,
103
+ opt[:name] = "EMP_STAT_CD" if opt[:name].nil?
104
+ opt[:valid_values] = /^(A|D|L|N|P|R|S|T)$/i if opt[:valid_values].nil?
105
+ return RsmartToolbox::ETL::parse_flag str, opt
106
+ end
107
+
108
+ def self.parse_emp_typ_cd(str, opt={})
109
+ # `EMP_TYP_CD` varchar(40) COLLATE utf8_bin DEFAULT NULL,
110
+ opt[:name] = "EMP_TYP_CD" if opt[:name].nil?
111
+ opt[:valid_values] = /^(N|O|P)$/i if opt[:valid_values].nil?
112
+ return RsmartToolbox::ETL::parse_flag str, opt
113
+ end
114
+
115
+ def self.parse_address_type_code(str, opt={})
116
+ # TODO find real column name
117
+ opt[:name] = "TODO_address_type_code" if opt[:name].nil?
118
+ opt[:length] = 3 if opt[:length].nil?
119
+ opt[:valid_values] = /^(HM|OTH|WRK)$/i if opt[:valid_values].nil?
120
+ return RsmartToolbox::ETL::parse_flag str, opt
121
+ end
122
+
123
+ def self.parse_name_code(str, opt={})
124
+ opt[:name] = "NM_TYP_CD" if opt[:name].nil?
125
+ opt[:length] = 4 if opt[:length].nil?
126
+ opt[:valid_values] = /^(OTH|PRFR|PRM)$/i if opt[:valid_values].nil?
127
+ return RsmartToolbox::ETL::parse_flag str, opt
128
+ end
129
+
130
+ def self.parse_prefix(str, opt={})
131
+ opt[:name] = "PREFIX_NM" if opt[:name].nil?
132
+ opt[:length] = 3 if opt[:length].nil?
133
+ opt[:valid_values] = /^(Ms|Mrs|Mr|Dr)?$/ if opt[:valid_values].nil?
134
+ opt[:upcase] = false if opt[:upcase].nil?
135
+ return RsmartToolbox::ETL::parse_flag str, opt
136
+ end
137
+
138
+ def self.parse_suffix(str, opt={})
139
+ opt[:name] = "SUFFIX_NM" if opt[:name].nil?
140
+ opt[:length] = 3 if opt[:length].nil?
141
+ opt[:valid_values] = /^(Jr|Sr|Mr|Md)?$/ if opt[:valid_values].nil?
142
+ opt[:upcase] = false if opt[:upcase].nil?
143
+ return RsmartToolbox::ETL::parse_flag str, opt
144
+ end
145
+
146
+ def self.parse_phone_type(str, opt={})
147
+ # TODO find real column name
148
+ opt[:name] = "TODO_phone_type" if opt[:name].nil?
149
+ opt[:length] = 3 if opt[:length].nil?
150
+ opt[:valid_values] = /^(FAX|HM|MBL|OTH|WRK)$/i if opt[:valid_values].nil?
151
+ return RsmartToolbox::ETL::parse_flag str, opt
152
+ end
153
+
154
+ def self.parse_phone_number(str, opt={})
155
+ # TODO find real column name
156
+ opt[:name] = "PHONE_NBR" if opt[:name].nil?
157
+ opt[:length] = 12 if opt[:length].nil?
158
+ opt[:valid_values] = /^(\d{3}-\d{3}-\d{4})?$/ if opt[:valid_values].nil?
159
+ return RsmartToolbox::ETL::parse_string str, opt
160
+ end
161
+
162
+ def self.parse_email_type(str, opt={})
163
+ opt[:name] = "EMAIL_TYP_CD" if opt[:name].nil?
164
+ opt[:length] = 3 if opt[:length].nil?
165
+ opt[:valid_values] = /^(HM|OTH|WRK)$/i if opt[:valid_values].nil?
166
+ return RsmartToolbox::ETL::parse_flag str, opt
167
+ end
168
+
169
+ def self.parse_year(str, opt={})
170
+ opt[:length] = 4 if opt[:length].nil?
171
+ opt[:valid_values] = /^(\d{4})?$/ if opt[:valid_values].nil?
172
+ return RsmartToolbox::ETL::parse_string str, opt
173
+ end
174
+
175
+ def self.parse_citizenship_type(str, opt={})
176
+ opt[:name] = "CITIZENSHIP_TYPE_CODE" if opt[:name].nil?
177
+ opt[:valid_values] = /^([1-4])$/ if opt[:valid_values].nil?
178
+ return RsmartToolbox::ETL::parse_flag str, opt
179
+ end
180
+
181
+ def self.parse_degree(str, opt={})
182
+ # TODO find real column name
183
+ opt[:name] = "DEGREE" if opt[:name].nil?
184
+ opt[:length] = 5 if opt[:length].nil?
185
+ opt[:valid_values] = /^(AS|BA|BComm|BEd|BS|DA|DC|DD|DDS|DEng|DFA|DH|DHA|DMin|DPA|DSN|DVM|DVS|HS|JD|LLD|LLM|MA|MAEd|MArch|MBA|MD|MDS|MDiv|MEE|MEd|MEng|MFA|MIS|MLS|MPA|MPE|MPH|MPd|MPhil|MS|MSEd|MST|MSW|MTh|PhD|PharD|ScD|ThD|UKNW)?$/ if opt[:valid_values].nil?
186
+ opt[:upcase] = false if opt[:upcase].nil?
187
+ return RsmartToolbox::ETL::parse_flag str, opt
188
+ end
189
+
190
+ end