caruby-core 1.4.7 → 1.4.9

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.
Files changed (48) hide show
  1. data/History.txt +11 -0
  2. data/README.md +1 -1
  3. data/lib/caruby/cli/command.rb +27 -3
  4. data/lib/caruby/csv/csv_mapper.rb +2 -0
  5. data/lib/caruby/csv/csvio.rb +187 -169
  6. data/lib/caruby/database.rb +33 -16
  7. data/lib/caruby/database/lazy_loader.rb +23 -23
  8. data/lib/caruby/database/persistable.rb +32 -18
  9. data/lib/caruby/database/persistence_service.rb +20 -7
  10. data/lib/caruby/database/reader.rb +22 -21
  11. data/lib/caruby/database/search_template_builder.rb +7 -9
  12. data/lib/caruby/database/sql_executor.rb +52 -27
  13. data/lib/caruby/database/store_template_builder.rb +18 -13
  14. data/lib/caruby/database/writer.rb +107 -44
  15. data/lib/caruby/domain/attribute_metadata.rb +35 -25
  16. data/lib/caruby/domain/java_attribute_metadata.rb +43 -20
  17. data/lib/caruby/domain/merge.rb +9 -5
  18. data/lib/caruby/domain/reference_visitor.rb +4 -3
  19. data/lib/caruby/domain/resource_attributes.rb +52 -12
  20. data/lib/caruby/domain/resource_dependency.rb +129 -42
  21. data/lib/caruby/domain/resource_introspection.rb +1 -1
  22. data/lib/caruby/domain/resource_inverse.rb +20 -3
  23. data/lib/caruby/domain/resource_metadata.rb +20 -4
  24. data/lib/caruby/domain/resource_module.rb +190 -124
  25. data/lib/caruby/import/java.rb +39 -19
  26. data/lib/caruby/migration/migratable.rb +31 -6
  27. data/lib/caruby/migration/migrator.rb +126 -40
  28. data/lib/caruby/migration/uniquify.rb +0 -1
  29. data/lib/caruby/resource.rb +28 -5
  30. data/lib/caruby/util/attribute_path.rb +0 -2
  31. data/lib/caruby/util/class.rb +8 -5
  32. data/lib/caruby/util/collection.rb +5 -3
  33. data/lib/caruby/util/domain_extent.rb +0 -3
  34. data/lib/caruby/util/options.rb +10 -9
  35. data/lib/caruby/util/person.rb +41 -12
  36. data/lib/caruby/util/pretty_print.rb +1 -1
  37. data/lib/caruby/util/validation.rb +0 -28
  38. data/lib/caruby/version.rb +1 -1
  39. data/test/lib/caruby/import/java_test.rb +26 -9
  40. data/test/lib/caruby/migration/test_case.rb +103 -0
  41. data/test/lib/caruby/test_case.rb +231 -0
  42. data/test/lib/caruby/util/class_test.rb +2 -2
  43. data/test/lib/caruby/util/visitor_test.rb +3 -2
  44. data/test/lib/examples/galena/clinical_trials/migration/participant_test.rb +28 -0
  45. data/test/lib/examples/galena/clinical_trials/migration/test_case.rb +40 -0
  46. metadata +195 -170
  47. data/lib/caruby/domain/attribute_initializer.rb +0 -16
  48. data/test/lib/caruby/util/validation_test.rb +0 -14
data/History.txt CHANGED
@@ -1,3 +1,6 @@
1
+ This history lists major release themes. See the GitHub source (https://github.com/caruby/core)
2
+ for change details.
3
+
1
4
  === 1.4.1 / 2010-11-23
2
5
 
3
6
  * Initial public release.
@@ -30,4 +33,12 @@
30
33
 
31
34
  * Support annotation migration.
32
35
 
36
+ === 1.4.8 / 2011-05-03
37
+
38
+ * Fix annotation migration error.
39
+
40
+ * Refactor resource import.
41
+
42
+ === 1.4.9 / 2011-05-04
33
43
 
44
+ * Support Oracle driver.
data/README.md CHANGED
@@ -27,7 +27,7 @@ Feature List
27
27
 
28
28
  Installing
29
29
  ----------
30
- caRuby is installed automatically when an application gem, e.g. caruby-tissue,
30
+ caRuby is installed automatically when an application gem, e.g. [caruby-tissue](http://caruby.rubyforge.org/catissue.html),
31
31
  is installed.
32
32
 
33
33
  Usage
@@ -47,8 +47,11 @@ module CaRuby
47
47
  # @yieldparam (see #run)
48
48
  def initialize(specs=[], &executor)
49
49
  @executor = executor
50
+ # Options start with a dash, arguments are whatever is left.
50
51
  @opt_specs, @arg_specs = specs.partition { |spec| spec[1][0, 1] == '-' }
52
+ # Add the default option specifications.
51
53
  @opt_specs.concat(DEF_OPTS)
54
+ # The application name is the command.
52
55
  super($0)
53
56
  end
54
57
 
@@ -70,6 +73,7 @@ module CaRuby
70
73
 
71
74
  private
72
75
 
76
+ # The default options that apply to all commands.
73
77
  DEF_OPTS = [
74
78
  [:help, "-h", "--help", "Display this help message"],
75
79
  [:file, "--file FILE", "Configuration file containing other options"],
@@ -78,6 +82,7 @@ module CaRuby
78
82
  [:quiet, "-q", "--quiet", "Suppress printing messages to stdout"]
79
83
  ]
80
84
 
85
+ # @param [{Symbol => Object}] opts the option => value hash
81
86
  def call_executor(opts)
82
87
  if @executor.nil? then raise CommandError.new("Command #{self} does not have an execution block") end
83
88
  @executor.call(opts)
@@ -87,14 +92,19 @@ module CaRuby
87
92
  #
88
93
  # @return [{Symbol => Object}] the option => value hash
89
94
  def get_opts
95
+ # the options hash
90
96
  opts = {}
91
97
  # the option parser
92
98
  OptionParser.new do |parser|
99
+ # The help argument string is comprised of the argument specification labels.
93
100
  arg_s = @arg_specs.map { |spec| spec[1] }.join(' ')
101
+ # Build the usage message.
94
102
  parser.banner = "Usage: #{parser.program_name} [options] #{arg_s}"
95
103
  parser.separator ""
96
104
  parser.separator "Options:"
105
+ # parse the options
97
106
  opts = parse(parser)
107
+ # grab the usage message
98
108
  @usage = parser.help
99
109
  end
100
110
  opts
@@ -105,22 +115,36 @@ module CaRuby
105
115
  # @return [{Symbol => Object}] the argument => value hash
106
116
  def get_args
107
117
  return Hash::EMPTY_HASH if ARGV.empty?
118
+ if @arg_specs.empty? then too_many_arguments end
119
+ # Collect the arguments from the command line.
108
120
  args = {}
121
+ # The number of command line arguments or all but the last argument specifications,
122
+ # whichever is less. The last argument can have more than one value, indicated by
123
+ # the argument specification form '...', so it is processed separately below.
109
124
  n = [ARGV.size, @arg_specs.size - 1].min
125
+ # the single-valued arguments
110
126
  n.times { |i| args[@arg_specs[i].first] = ARGV[i] }
127
+ # Process the last argument.
111
128
  if n < ARGV.size then
112
129
  arg, form = @arg_specs.last
130
+ # A multi-valued last argument is the residual command argument array.
131
+ # A single-valued last argument is the last value, if there is exactly one.
132
+ # Otherwise, there are too many arguments.
113
133
  if form.index('...') then
114
134
  args[arg] = ARGV[n..-1]
115
135
  elsif @arg_specs.size == ARGV.size then
116
136
  args[arg] = ARGV[n]
117
137
  else
118
- halt("Too many arguments", 1)
138
+ too_many_arguments
119
139
  end
120
140
  end
121
141
  args
122
142
  end
123
143
 
144
+ def too_many_arguments
145
+ halt("Too many arguments - expected #{@arg_specs.size}, found: #{ARGV.join(' ')}.", 1)
146
+ end
147
+
124
148
  # @param [OptionParser] parser the option parser
125
149
  # @return [{Symbol => Object}] the option => value hash
126
150
  def parse(parser)
@@ -167,8 +191,8 @@ module CaRuby
167
191
 
168
192
  # Prints the given message and program usage, then exits with the given status.
169
193
  def halt(message=nil, status=0)
170
- print(message) if message
171
- print(@usage)
194
+ puts(message) if message
195
+ puts(@usage)
172
196
  exit(status)
173
197
  end
174
198
  end
@@ -3,6 +3,8 @@ require 'caruby/util/properties'
3
3
 
4
4
  module CaRuby
5
5
  # Maps a CSV extract to a caBIG application.
6
+ #
7
+ # _Note_: CsvMapper is an experimental class used only by the CaTissue::Extractor.
6
8
  class CsvMapper
7
9
  attr_reader :csvio, :classes
8
10
 
@@ -6,180 +6,198 @@ require 'faster_csv'
6
6
  require 'caruby/util/options'
7
7
  require 'caruby/util/collection'
8
8
 
9
- # CsvIO reads or writes CSV records.
10
- # This class wraps a FasterCSV with the following modifications:
11
- # * relax the date parser to allow dd/mm/yyyy dates
12
- # * don't convert integer text with a leading zero to an octal number
13
- # * allow one custom converter with different semantics: if the converter block
14
- # call returns nil, then continue conversion, otherwise return the converter
15
- # result. This differs from FasterCSV converter semantics which calls converters
16
- # as long the result == the input field value. The CsvIO converter semantics
17
- # supports converters that intend a String result to be the converted result.
18
- #
19
- # CsvIO is Enumerable, but does not implement the complete Ruby IO interface.
20
- class CsvIO
21
- include Enumerable
22
-
23
- # Returns the CSV field access header symbols.
24
- attr_reader :headers
25
-
26
- # Opens the CSV file and calls the given block with this CsvIO as the argument.
9
+ module CaRuby
10
+ # CsvIO reads or writes CSV records.
11
+ # This class wraps a FasterCSV with the following modifications:
12
+ # * relax the date parser to allow dd/mm/yyyy dates
13
+ # * don't convert integer text with a leading zero to an octal number
14
+ # * allow one custom converter with different semantics: if the converter block
15
+ # call returns nil, then continue conversion, otherwise return the converter
16
+ # result. This differs from FasterCSV converter semantics which calls converters
17
+ # as long the result == the input field value. The CsvIO converter semantics
18
+ # supports converters that intend a String result to be the converted result.
27
19
  #
28
- # @see #initialize the supported options
29
- def self.open(file, options=nil) # :yields: csvio
30
- csvio = self.new(file, options)
31
- if block_given? then
32
- yield csvio
33
- csvio.close
20
+ # CsvIO is Enumerable, but does not implement the complete Ruby IO interface.
21
+ class CsvIO
22
+ include Enumerable
23
+
24
+ # Returns the CSV field access header symbols.
25
+ attr_reader :headers
26
+
27
+ # Opens the CSV file and calls the given block with this CsvIO as the argument.
28
+ #
29
+ # @param (see #initialize)
30
+ # @option (see #initialize)
31
+ # @yield [csvio] the optional block to execute
32
+ # @yieldparam [CsvIO] csvio the open CSVIO instance
33
+ def self.open(file, opts=nil)
34
+ csvio = new(file, opts)
35
+ if block_given? then
36
+ yield csvio
37
+ csvio.close
38
+ end
34
39
  end
35
- end
36
-
37
- # #open the given CSV file and options, and call {#each} with the given block.
38
- def self.foreach(file, options=nil, &block) # :yields: record
39
- self.open(file, options=nil) { |csvio| csvio.each(&block) }
40
- end
41
-
42
- # Creates a new CsvIO for the specified source file.
43
- # If a converter block is given, then it is added to the CSV converters list.
44
- def initialize(file, options=nil, &converter)
45
- # the CSV file open mode
46
- mode = Options.get(:mode, options, "r")
47
- # the CSV headers option; can be boolean or array
48
- hdr_opt = Options.get(:headers, options)
49
- # there is a header record by default for an input CSV file
50
- hdr_opt ||= true if mode =~ /^r/
51
- # make parent directories if necessary for an output CSV file
52
- File.makedirs(File.dirname(file)) if mode =~ /^w/
53
- # if headers aren't given, then convert the input CSV header record names to underscore symbols
54
- hdr_cvtr = :symbol unless Enumerable === hdr_opt
55
- # make a custom converter
56
- custom = Proc.new { |f, info| convert(f, info, &converter) }
57
- # open the CSV file
58
- @csv = FasterCSV.open(file, mode, :headers => hdr_opt, :header_converters => hdr_cvtr, :return_headers => true, :write_headers => true, :converters => custom)
59
- # the header => field name hash:
60
- # if the header option is set to true, then read the input header line.
61
- # otherwise, parse an empty string which mimics an input header line.
62
- hdr_row = case hdr_opt
63
- when true then
40
+
41
+ # {#open}s the given CSV file and calls {#each} with the given block.
42
+ #
43
+ # @param (see #initialize)
44
+ # @option (see #initialize)
45
+ # @yield [row] the block to execute on the row
46
+ # @yieldparam [{Symbol => Object}] row the field symbol => value hash
47
+ def self.foreach(file, opts=nil, &block)
48
+ open(file, opts) { |csvio| csvio.each(&block) }
49
+ end
50
+
51
+ # Creates a new CsvIO for the specified source file.
52
+ # If a converter block is given, then it is added to the CSV converters list.
53
+ #
54
+ # @param [String] file the input CSV file to open
55
+ # @param [Hash] opts the open options
56
+ # @option opts [String] :mode the input mode (default +r+)
57
+ # @option opts [String] :headers the input field headers
58
+ # @yield [value, info] converts the input value
59
+ # @yieldparam [String] value the input value
60
+ # @yieldparam info the current field's FasterCSV FieldInfo metadata
61
+ def initialize(file, opts=nil, &converter)
62
+ # the CSV file open mode
63
+ mode = Options.get(:mode, opts, 'r')
64
+ # the CSV headers option; can be boolean or array
65
+ hdr_opt = Options.get(:headers, opts)
66
+ # there is a header record by default for an input CSV file
67
+ hdr_opt ||= true if mode =~ /^r/
68
+ # make parent directories if necessary for an output CSV file
69
+ File.makedirs(File.dirname(file)) if mode =~ /^w/
70
+ # if headers aren't given, then convert the input CSV header record names to underscore symbols
71
+ hdr_cvtr = :symbol unless Enumerable === hdr_opt
72
+ # make a custom converter
73
+ custom = Proc.new { |value, info| convert(value, info, &converter) }
74
+ # open the CSV file
75
+ @csv = FasterCSV.open(file, mode, :headers => hdr_opt, :header_converters => hdr_cvtr, :return_headers => true, :write_headers => true, :converters => custom)
76
+ # the header => field name hash:
77
+ # if the header option is set to true, then read the input header line.
78
+ # otherwise, parse an empty string which mimics an input header line.
79
+ hdr_row = case hdr_opt
80
+ when true then
81
+ @csv.shift
82
+ when Enumerable then
83
+ ''.parse_csv(:headers => hdr_opt, :header_converters => :symbol, :return_headers => true)
84
+ else
85
+ raise ArgumentError.new("CSV headers option value not supported: #{hdr_opt}")
86
+ end
87
+ # the header row headers
88
+ @headers = hdr_row.headers
89
+ # the header name => symbol map
90
+ @hdr_sym_hash = hdr_row.to_hash.invert
91
+ end
92
+
93
+ # Closes the CSV file and trash file if necessary.
94
+ def close
95
+ @csv.close
96
+ @trash.close if @trash
97
+ end
98
+
99
+ # Returns the header accessor method for the given input header name.
100
+ def accessor(header)
101
+ @hdr_sym_hash[header]
102
+ end
103
+
104
+ # Sets the trash output file. This creates a separate CSV output file distinct from the input CSV file.
105
+ # This is useful for writing rejected rows from the input. The output file has a header row.
106
+ def trash=(file)
107
+ @trash = FasterCSV.open(file, 'w', :headers => true, :header_converters => :symbol, :write_headers => true)
108
+ end
109
+
110
+ # Writes the row to the trash file if the trash file is set.
111
+ #
112
+ #@param [{Symbol => Object}] row the rejected input row
113
+ def reject(row)
114
+ @trash << row if @trash
115
+ end
116
+
117
+ # Iterates over each CSV row, yielding a row for each iteration.
118
+ # This method closes the CSV file after the iteration completes.
119
+ def each
120
+ begin
121
+ # parse each line
122
+ @csv.each { |row| yield row }
123
+ ensure
124
+ close
125
+ end
126
+ end
127
+
128
+ # @return the next CSV row
129
+ # @see #each
130
+ def read
64
131
  @csv.shift
65
- when Enumerable then
66
- ''.parse_csv(:headers => hdr_opt, :header_converters => :symbol, :return_headers => true)
67
- else
68
- raise ArgumentError.new("CSV headers option value not supported: #{hdr_opt}")
69
132
  end
70
- # the header row headers
71
- @headers = hdr_row.headers
72
- # the header name => symbol map
73
- @hdr_sym_hash = hdr_row.to_hash.invert
74
- end
75
-
76
- # Closes the CSV file and trash file if necessary.
77
- def close
78
- @csv.close
79
- @trash.close if @trash
80
- end
81
-
82
- # Returns the header accessor method for the given input header name.
83
- def accessor(header)
84
- @hdr_sym_hash[header]
85
- end
86
-
87
- # Sets the trash output file. This creates a separate CSV output file distinct from the input CSV file.
88
- # This is useful for writing rejected rows from the input. The output file has a header row.
89
- def trash=(file)
90
- @trash = FasterCSV.open(file, 'w', :headers => true, :header_converters => :symbol, :write_headers => true)
91
- end
92
-
93
- # Writes the row to the trash file if the trash file is set.
94
- #
95
- #@param [{Symbol => Object}] row the rejected input row
96
- def reject(row)
97
- @trash << row if @trash
98
- end
99
-
100
- # Iterates over each CSV row, yielding a row for each iteration.
101
- # This method closes the CSV file after the iteration completes.
102
- def each
103
- begin
104
- # parse each line
105
- @csv.each { |row| yield row }
106
- ensure
107
- close
133
+
134
+ alias :shift :read
135
+
136
+ # Writes the given row to the CSV file.
137
+ #
138
+ #@param [{Symbol => Object}] row the input row
139
+ def write(row)
140
+ @csv << row
108
141
  end
109
- end
110
-
111
- # @return the next CSV row
112
- # @see #each
113
- def read
114
- @csv.shift
115
- end
116
-
117
- alias :shift :read
118
-
119
- # Writes the given row to the CSV file.
120
- #
121
- #@param [{Symbol => Object}] row the input row
122
- def write(row)
123
- @csv << row
124
- end
125
-
126
- alias :<< :write
127
-
128
- private
129
-
130
- # 3-letter months => month sequence hash.
131
- MMM_MM_MAP = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'].to_compact_hash_with_index do |mmm, index|
132
- index < 9 ? ('0' + index.succ.to_s) : index.succ.to_s
133
- end
134
-
135
- # DateMatcher relaxes the FasterCSV DateMatcher to allow dd/mm/yyyy dates.
136
- DateMatcher = / \A(?: (\w+,?\s+)?\w+\s+\d{1,2},?\s+\d{2,4} | \d{1,2}-\w{3}-\d{2,4} | \d{4}[-\/]\d{1,2}[-\/]\d{1,2} | \d{1,2}[-\/]\d{1,2}[-\/]\d{2,4} )\z /x
137
-
138
- # @param f the input field value to convert
139
- # @param info the CSV field info
140
- # @return the converted value
141
- def convert(f, info)
142
- return if f.nil?
143
- # the block has precedence
144
- value = yield(f, info) if block_given?
145
- # integer conversion
146
- value ||= Integer(f) if f =~ /^[1-9]\d*$/
147
- # date conversion
148
- value ||= convert_date(f) if f =~ CsvIO::DateMatcher
149
- # float conversion
150
- value ||= (Float(f) rescue f) if f =~ /^\d+\.\d*$/ or f =~ /^\d*\.\d+$/
151
- # return converted value or the input field if there was no conversion
152
- value || f
153
- end
154
-
155
- # @param [String] the input field value
156
- # @return [Date] the converted date
157
- def convert_date(f)
158
- # If input value is in dd-mmm-yy format, then reformat.
159
- # Otherwise, parse as a Date if possible.
160
- if f =~ /^\d{1,2}-\w{3}-\d{2,4}$/ then
161
- ddmmyy = reformat_dd_mmm_yy_date(f) || return
162
- convert_date(ddmmyy)
163
- # elsif f =~ /^\w{3} \d{1,2}, \d{4}$/ then
164
- # ddmmyy = reformat_mmm_dd_yyyy_date(f) || return
165
- # convert_date(ddmmyy)
166
- else
167
- Date.parse(f, true) rescue nil
142
+
143
+ alias :<< :write
144
+
145
+ private
146
+
147
+ # 3-letter months => month sequence hash.
148
+ MMM_MM_MAP = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'].to_compact_hash_with_index do |mmm, index|
149
+ index < 9 ? ('0' + index.succ.to_s) : index.succ.to_s
168
150
  end
151
+
152
+ # DateMatcher relaxes the FasterCSV DateMatcher to allow dd/mm/yyyy dates.
153
+ DateMatcher = / \A(?: (\w+,?\s+)?\w+\s+\d{1,2},?\s+\d{2,4} | \d{1,2}-\w{3}-\d{2,4} | \d{4}[-\/]\d{1,2}[-\/]\d{1,2} | \d{1,2}[-\/]\d{1,2}[-\/]\d{2,4} )\z /x
154
+
155
+ # @param f the input field value to convert
156
+ # @param info the CSV field info
157
+ # @return the converted value
158
+ def convert(f, info)
159
+ return if f.nil?
160
+ # the block has precedence
161
+ value = yield(f, info) if block_given?
162
+ # integer conversion
163
+ value ||= Integer(f) if f =~ /^[1-9]\d*$/
164
+ # date conversion
165
+ value ||= convert_date(f) if f =~ CsvIO::DateMatcher
166
+ # float conversion
167
+ value ||= (Float(f) rescue f) if f =~ /^\d+\.\d*$/ or f =~ /^\d*\.\d+$/
168
+ # return converted value or the input field if there was no conversion
169
+ value || f
170
+ end
171
+
172
+ # @param [String] the input field value
173
+ # @return [Date] the converted date
174
+ def convert_date(f)
175
+ # If input value is in dd-mmm-yy format, then reformat.
176
+ # Otherwise, parse as a Date if possible.
177
+ if f =~ /^\d{1,2}-\w{3}-\d{2,4}$/ then
178
+ ddmmyy = reformat_dd_mmm_yy_date(f) || return
179
+ convert_date(ddmmyy)
180
+ # elsif f =~ /^\w{3} \d{1,2}, \d{4}$/ then
181
+ # ddmmyy = reformat_mmm_dd_yyyy_date(f) || return
182
+ # convert_date(ddmmyy)
183
+ else
184
+ Date.parse(f, true) rescue nil
185
+ end
186
+ end
187
+
188
+ # @param [String] the input field value in dd-mmm-yy format
189
+ # @return [String] the reformatted date String in mm/dd/yy format
190
+ def reformat_dd_mmm_yy_date(f)
191
+ all, dd, mmm, yy = /^(\d{1,2})-([[:alpha:]]{3})-(\d{2,4})$/.match(f).to_a
192
+ mm = MMM_MM_MAP[mmm.downcase] || return
193
+ "#{mm}/#{dd}/#{yy}"
194
+ end
195
+ # # @param [String] the input field value in 'mmmd d, yyyy' format
196
+ # # @return [String] the reformatted date String in mm/dd/yyyy format
197
+ # def reformat_mmm_dd_yyyy_date(f)
198
+ # all, mmm, dd, yyyy = /^(\w{3}) (\d{1,2}), (\d{4})$/.match(f).to_a
199
+ # mm = MMM_MM_MAP[mmm.downcase] || return
200
+ # "#{mm}/#{dd}/#{yyyy}"
201
+ # end
169
202
  end
170
-
171
- # @param [String] the input field value in dd-mmm-yy format
172
- # @return [String] the reformatted date String in mm/dd/yy format
173
- def reformat_dd_mmm_yy_date(f)
174
- all, dd, mmm, yy = /^(\d{1,2})-([[:alpha:]]{3})-(\d{2,4})$/.match(f).to_a
175
- mm = MMM_MM_MAP[mmm.downcase] || return
176
- "#{mm}/#{dd}/#{yy}"
177
- end
178
- # # @param [String] the input field value in 'mmmd d, yyyy' format
179
- # # @return [String] the reformatted date String in mm/dd/yyyy format
180
- # def reformat_mmm_dd_yyyy_date(f)
181
- # all, mmm, dd, yyyy = /^(\w{3}) (\d{1,2}), (\d{4})$/.match(f).to_a
182
- # mm = MMM_MM_MAP[mmm.downcase] || return
183
- # "#{mm}/#{dd}/#{yyyy}"
184
- # end
185
203
  end