caruby-core 1.4.9 → 1.5.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.
Files changed (61) hide show
  1. data/History.md +48 -0
  2. data/lib/caruby/cli/command.rb +2 -1
  3. data/lib/caruby/csv/csv_mapper.rb +8 -8
  4. data/lib/caruby/database/persistable.rb +44 -65
  5. data/lib/caruby/database/persistence_service.rb +12 -9
  6. data/lib/caruby/database/persistifier.rb +14 -14
  7. data/lib/caruby/database/reader.rb +53 -51
  8. data/lib/caruby/database/search_template_builder.rb +9 -10
  9. data/lib/caruby/database/store_template_builder.rb +58 -58
  10. data/lib/caruby/database/writer.rb +96 -96
  11. data/lib/caruby/database.rb +19 -19
  12. data/lib/caruby/domain/attribute.rb +581 -0
  13. data/lib/caruby/domain/attributes.rb +615 -0
  14. data/lib/caruby/domain/dependency.rb +240 -0
  15. data/lib/caruby/domain/importer.rb +183 -0
  16. data/lib/caruby/domain/introspection.rb +176 -0
  17. data/lib/caruby/domain/inverse.rb +173 -0
  18. data/lib/caruby/domain/inversible.rb +1 -2
  19. data/lib/caruby/domain/java_attribute.rb +173 -0
  20. data/lib/caruby/domain/merge.rb +13 -10
  21. data/lib/caruby/domain/metadata.rb +141 -0
  22. data/lib/caruby/domain/mixin.rb +35 -0
  23. data/lib/caruby/domain/reference_visitor.rb +5 -3
  24. data/lib/caruby/domain.rb +340 -0
  25. data/lib/caruby/import/java.rb +29 -25
  26. data/lib/caruby/migration/migratable.rb +5 -5
  27. data/lib/caruby/migration/migrator.rb +19 -15
  28. data/lib/caruby/migration/resource_module.rb +1 -1
  29. data/lib/caruby/resource.rb +39 -30
  30. data/lib/caruby/util/collection.rb +94 -33
  31. data/lib/caruby/util/coordinate.rb +28 -2
  32. data/lib/caruby/util/log.rb +4 -4
  33. data/lib/caruby/util/module.rb +12 -28
  34. data/lib/caruby/util/partial_order.rb +9 -10
  35. data/lib/caruby/util/pretty_print.rb +46 -26
  36. data/lib/caruby/util/topological_sync_enumerator.rb +10 -4
  37. data/lib/caruby/util/transitive_closure.rb +2 -2
  38. data/lib/caruby/util/visitor.rb +1 -1
  39. data/lib/caruby/version.rb +1 -1
  40. data/test/lib/caruby/database/persistable_test.rb +1 -1
  41. data/test/lib/caruby/domain/domain_test.rb +14 -28
  42. data/test/lib/caruby/domain/inversible_test.rb +1 -1
  43. data/test/lib/caruby/import/java_test.rb +5 -0
  44. data/test/lib/caruby/migration/test_case.rb +0 -1
  45. data/test/lib/caruby/test_case.rb +9 -10
  46. data/test/lib/caruby/util/collection_test.rb +23 -5
  47. data/test/lib/caruby/util/module_test.rb +10 -14
  48. data/test/lib/caruby/util/partial_order_test.rb +16 -15
  49. data/test/lib/caruby/util/visitor_test.rb +1 -1
  50. data/test/lib/examples/galena/clinical_trials/migration/test_case.rb +1 -1
  51. metadata +16 -15
  52. data/History.txt +0 -44
  53. data/lib/caruby/domain/attribute_metadata.rb +0 -551
  54. data/lib/caruby/domain/java_attribute_metadata.rb +0 -183
  55. data/lib/caruby/domain/resource_attributes.rb +0 -565
  56. data/lib/caruby/domain/resource_dependency.rb +0 -217
  57. data/lib/caruby/domain/resource_introspection.rb +0 -160
  58. data/lib/caruby/domain/resource_inverse.rb +0 -151
  59. data/lib/caruby/domain/resource_metadata.rb +0 -155
  60. data/lib/caruby/domain/resource_module.rb +0 -370
  61. data/lib/caruby/yard/resource_metadata_handler.rb +0 -8
@@ -0,0 +1,340 @@
1
+ require 'fileutils'
2
+ require 'caruby/util/collection'
3
+ require 'caruby/util/log'
4
+ require 'caruby/domain/importer'
5
+
6
+ module CaRuby
7
+ class JavaImportError < StandardError; end;
8
+
9
+ # The application and database connection access command line options.
10
+ ACCESS_OPTS = [
11
+ [:user, "--user USER", "the application login user"],
12
+ [:password, "--password PSWD", "the application login password"],
13
+ [:host, "--host HOST", "the application host name"],
14
+ [:port, "--port PORT", "the application port number"],
15
+ [:classpath, "--classpath PATH", "the application client classpath"],
16
+ [:database_host, "--database_host HOST", "the database host name"],
17
+ [:database_type, "--database_type TYPE", "the database type (mysql or oracle)"],
18
+ [:database_driver, "--database_driver DRIVER", "the database driver string"],
19
+ [:database_driver_class, "--database_driver_class CLASS", "the database driver class name"],
20
+ [:database_port, "--database_port PORT", Integer, "the database port number"],
21
+ [:database, "--database NAME", "the database name"],
22
+ [:database_user, "--database_user USER", "the database login user"],
23
+ [:database_password, "--database_password PSWD", "the database login password"]
24
+ ]
25
+
26
+ # Domain extends a Module with Java class {Metadata} support.
27
+ #
28
+ # A Java class is imported into Ruby either by including the given Resource module
29
+ # or by referenceing the class name for the first time. For example, the
30
+ # +ClinicalTrials+ wrapper for Java package +org.nci.ctms+ classes and
31
+ # Ruby class definitions in the +domain+ subdirectory is enabled as follows:
32
+ # module ClinicalTrials
33
+ # PKG = 'org.nci.ctms'
34
+ # SRC_DIR = File.join(File.dirname(__FILE__), 'domain')
35
+ # CaRuby::Domain.extend_module(self, :package => PKG, :directory => SRC_DIR)
36
+ #
37
+ # The first reference by name to +ClinicalTrials::Subject+ imports the Java class
38
+ # +org.nci.ctms.Subject+ into +ClinicalTrials+. The +Subject+ Java property meta-data
39
+ # is introspected and the {Resource} module is included.
40
+ module Domain
41
+ # Extends the given module with importable Java class {Metadata} support.
42
+ #
43
+ # @param [Module] mod the module to extend
44
+ # @param [{Symbol => Object}] opts the extension options
45
+ # @option opts [Module] :metadata the optional {Metadata} extension (default {Metadata})
46
+ # @option opts [Module] :mixin the optional mix-in module (default {Resource})
47
+ # @option opts [String] :package the required Java package name
48
+ # @option opts [String] :directory the optional directory of source class definitions to load
49
+ def self.extend_module(mod, opts)
50
+ mod.extend(self)
51
+ Importer.extend_module(mod, opts)
52
+ end
53
+
54
+ # Loads the {#access_properties} and adds the +path+ property items to the Java classpath.
55
+ #
56
+ # @param [Module] mod the module to extend
57
+ def self.extended(mod)
58
+ super
59
+ mod.ensure_classpath_defined
60
+ end
61
+
62
+ # Loads the application start-up properties on demand. The properties are defined in the properties
63
+ # file or as environment variables.
64
+ # The properties file path is a period followed by the lower-case application name in the home directory,
65
+ # e.g. +~/.clincaltrials+ for the +ClinicalTrials+ application.
66
+ #
67
+ # The property file format is a series of property definitions in the form _property_: _value_.
68
+ # The supported properties include the following:
69
+ # * +host+ - the application server host (default +localhost+)
70
+ # * +port+ - the application server port (default +8080+)
71
+ # * +user+ - the application server login
72
+ # * +password+ - the application service password
73
+ # * +path+ or +classpath+ - the application client Java directories
74
+ # * +database+ - the application database name
75
+ # * +database_user+ - the application database connection userid
76
+ # * +database_password+ - the application database connection password
77
+ # * +database_host+ - the application database connection host (default +localhost+)
78
+ # * +database_type+ - the application database type, + mysql+ or +oracle+ (default +mysql+)
79
+ # * +database_driver+ - the application database connection driver (default is the database type default)
80
+ # * +database_port+ - the application database connection port (default is the database type default)
81
+ #
82
+ # The +path+ value is one or more directories separated by a semi-colon(;) or colon (:)
83
+ # Each path directory and all jar files within the directory are added to the caRuby execution
84
+ # Java classpath.
85
+ #
86
+ # Each property has an environment variable counterpart given by
87
+ #
88
+ # @return [{Symbol => Object}] the caBIG application access properties
89
+ def access_properties
90
+ @rsc_props ||= load_access_properties
91
+ end
92
+
93
+ # Ensures that the application client classpath is defined. The classpath is defined
94
+ # in the {#access_properties}. This method is called when a module extends this
95
+ # Domain, before any application Java domain class is imported into JRuby.
96
+ def ensure_classpath_defined
97
+ # Loading the access properties on demand sets the classpath.
98
+ access_properties
99
+ end
100
+
101
+ # # @param [Class, String] class_or_name the class to import into this module
102
+ # # @return [Class] the imported {Resource} class
103
+ # def resource_import(class_or_name)
104
+ # java_import(class_or_name)
105
+ # klass = Class.to_ruby(class_or_name)
106
+ # add_class(klass)
107
+ # klass
108
+ # end
109
+ #
110
+ # # @param [String] the class name to check
111
+ # # @eturn [Class, nil] the domain class for the class name, or nil if none in this module
112
+ # def domain_type_with_name(name)
113
+ # pkg, base = Java.split_class_name(name)
114
+ # return unless pkg.nil? or pkg == @java_package
115
+ # begin
116
+ # type = const_get(base)
117
+ # rescue JavaImportError => e
118
+ # # no such domain type; not an error.
119
+ # # other exceptions indicate that there was a domain type but could not be loaded; these exceptions propagate up the call stack
120
+ # logger.debug { "#{$!}" }
121
+ # return
122
+ # end
123
+ # type if type < Resource
124
+ # end
125
+
126
+ private
127
+
128
+ # # Adds the given class to this domain module. The class is extended with {Metadata} methods.
129
+ # #
130
+ # # @param [Class] the {Resource} class to add
131
+ # def add_class(klass)
132
+ # # This domain module's known Resource classes.
133
+ # @rsc_classes ||= Set.new
134
+ # # Bail if already added.
135
+ # return if @rsc_classes.include?(klass)
136
+ #
137
+ # logger.debug { "Adding #{klass.java_class.name} to #{qp}..." }
138
+ # # Add metadata to the class. This is done before adding the superclass and
139
+ # # referenced metadata, since they in turn might reference the current class
140
+ # # metadata.
141
+ # Metadata.extend_class(klass, self)
142
+ # # Add the class to the known Resource class set.
143
+ # @rsc_classes << klass
144
+ #
145
+ # # Make the superclass a Resource, if necessary.
146
+ # sc = klass.superclass
147
+ # unless @rsc_classes.include?(sc) then
148
+ # # the domain module includes the superclass on demand
149
+ # pkg, sym = Java.split_class_name(sc)
150
+ # if pkg == @java_package then
151
+ # # Load the superclass on demand; don't need to make this class a Resource,
152
+ # # but do need to import the class.
153
+ # const_get(sym)
154
+ # else
155
+ # # Superclass is not a member of the domain package; make this class a Resource.
156
+ # mod = @mixin
157
+ # klass.class_eval { include mod }
158
+ # end
159
+ # end
160
+ #
161
+ # # Add referenced domain classes as necessary.
162
+ # klass.each_attribute_metadata do |attr_md|
163
+ # ref = attr_md.type
164
+ # next if @rsc_classes.include?(ref)
165
+ # pkg, sym = Java.split_class_name(ref)
166
+ # # This domain module adds a referenced Domain class on demand.
167
+ # if pkg == @java_package then
168
+ # puts "rm ac1 #{klass} #{attr_md} -> #{ref}..."
169
+ # logger.debug { "Loading #{klass.qp} #{attr_md} reference #{ref.qp}" }
170
+ # const_get(sym)
171
+ # end
172
+ # end
173
+ #
174
+ # # Invoke the callback.
175
+ # class_added(klass)
176
+ # logger.debug { "#{klass.java_class.name} added to #{qp}." }
177
+ # # print the class structure to the log
178
+ # logger.info(klass.pp_s)
179
+ # end
180
+ #
181
+ # # Callback invoked after the given domain class is added to this domain module.
182
+ # #
183
+ # # @param [Class] klass the class that was added
184
+ # def class_added(klass); end
185
+
186
+ # Loads the application start-up properties in the given file path.
187
+ #
188
+ # @return (see #access_properties)
189
+ def load_access_properties
190
+ # the properties file
191
+ file = default_properties_file
192
+ # the access properties
193
+ props = file && File.exists?(file) ? load_properties_file(file) : {}
194
+ # Look for environment overrides preceded by the uppercase module name,
195
+ # e.g. CATISSUE_USER for the CaTissue module.
196
+ load_environment_properties(props)
197
+
198
+ # load the Java application jar path
199
+ path = props[:classpath] || props[:path]
200
+ if path then
201
+ logger.info("Defining application classpath #{path}...")
202
+ Java.add_path(path)
203
+ end
204
+
205
+ props
206
+ end
207
+
208
+ def load_properties_file(file)
209
+ props = {}
210
+ logger.info("Loading application properties from #{file}...")
211
+ File.open(file).map do |line|
212
+ # match the tolerant property definition
213
+ match = PROP_DEF_REGEX.match(line.chomp.strip) || next
214
+ # the property [name, value] tokens
215
+ tokens = match.captures
216
+ pname = tokens.first.to_sym
217
+ # path is deprecated
218
+ name = pname == :path ? :classpath : pname
219
+ value = tokens.last
220
+ # capture the property
221
+ props[name] = value
222
+ end
223
+ props
224
+ end
225
+
226
+ def load_environment_properties(props)
227
+ ACCESS_OPTS.each do |spec|
228
+ # the access option symbol is the first specification item
229
+ opt = spec[0]
230
+ # the envvar value
231
+ value = environment_property(opt) || next
232
+ # override the file property with the envar value
233
+ props[opt] = value
234
+ logger.info("Set application property #{opt} from environment variable #{ev}.")
235
+ end
236
+ end
237
+
238
+ # @param [Symbol] opt the property symbol, e.g. :user
239
+ # @return [String, nil] the value of the corresponding environment variable, e.g. +CATISSUE_USER+
240
+ def environment_property(opt)
241
+ @env_prefix ||= name.gsub('::', '_').upcase
242
+ ev = "#{@env_prefix}_#{opt.to_s.upcase}"
243
+ value = ENV[ev]
244
+ # If no classpath envvar, then try the deprecated path envvar.
245
+ if value.nil? and opt == :classpath then
246
+ environment_property(:path)
247
+ else
248
+ value
249
+ end
250
+ end
251
+ #
252
+ # # Imports the domain Java class with specified class name_or_sym.
253
+ # # This method enables the domain class extensions for storing and retrieving domain objects.
254
+ # # The class is added to this module.
255
+ # #
256
+ # # The optional block overrides the native Java property access wrappers.
257
+ # # For example:
258
+ # # ClinicalTrials.java_import Java::edu.wustl.catissuecore.domain.Study do
259
+ # # def study_code=(value)
260
+ # # value = value.to_s if Integer === value
261
+ # # setStudyCode(value)
262
+ # # end
263
+ # # end
264
+ # # imports the ClinicalTrials Study class as ClinicalTrials::Study and overrides the
265
+ # # +study_code+ setter method.
266
+ # #
267
+ # # Convenience aliases are added to the imported class, e.g. attribute +studyParticipantCollection+
268
+ # # is aliased as +study_participants+. Specifically, each attribute reader and writer is aliased with
269
+ # # the lower-case, underscore equivalent and a name ending in 'Collection' is changed to plural.
270
+ # # Pluralization is smart, e.g. +studyCollection+ is aliased to +studies+ rather than +studys+.
271
+ # #
272
+ # # The optional aliases argument consists of additional alias => standard attribute associations.
273
+ # # The optional owner_attr argument is a non-Java annotation owner attribute.
274
+ # #
275
+ # # @param [Symbol] symbol the class symbol
276
+ # # @param [String, nil] pkg the Java class package name, or nil for the default module package
277
+ # # @return [Class] the imported domain class
278
+ # def import_domain_class(symbol, pkg=nil)
279
+ # # import the Java class
280
+ # pkg ||= @java_package
281
+ # name = [pkg, symbol.to_s].join('.')
282
+ # logger.debug { "Detecting whether #{symbol} is a #{pkg} Java class..." }
283
+ # # Push each imported class onto a stack. When all referenced classes are imported,
284
+ # # each class on the stack is post-initialized and the class structure is printed to
285
+ # # the log.
286
+ # @import_stack ||= []
287
+ # @import_stack.push(symbol)
288
+ # begin
289
+ # resource_import(name)
290
+ # ensure
291
+ # @import_stack.pop
292
+ # end
293
+ #
294
+ # # the imported Java class is registered as a constant in this module
295
+ # klass = const_get(symbol)
296
+ # add_class(klass)
297
+ #
298
+ # # if we are back to top of the stack, then print the imported Resources
299
+ # if symbol == @import_stack.first then
300
+ # # a referenced class could be imported on demand in the course of printing a referencing class;
301
+ # # the referenced class is then pushed onto the stack. thus, the stack can grow during the
302
+ # # course of printing, but each imported class is consumed and printed in the end.
303
+ # until @import_stack.empty? do
304
+ # # the class constant
305
+ # sym = @import_stack.pop
306
+ # # the imported class
307
+ # kls = const_get(sym)
308
+ # # print the class structure to the log
309
+ # logger.info(kls.pp_s)
310
+ # end
311
+ # end
312
+ #
313
+ # klass
314
+ # end
315
+
316
+ # The property/value matcher, e.g.:
317
+ # host: jacardi
318
+ # host = jacardi
319
+ # host=jacardi
320
+ # name: J. Edgar Hoover
321
+ # but not:
322
+ # # host: jacardi
323
+ # The captures are the trimmed property and value.
324
+ PROP_DEF_REGEX = /^(\w+)(?:\s*[:=]\s*)([^#]+)/
325
+
326
+ # @return [String] the default application properties file, given by +~/.+_name_,
327
+ # where _name_ is the underscore unqualified module name, e.g. +~/.catissue+
328
+ # for module +CaTissue+
329
+ def default_properties_file
330
+ home = ENV['HOME'] || ENV['USERPROFILE'] || '~'
331
+ file = File.expand_path("#{home}/.#{name[/\w+$/].downcase}")
332
+ if File.exists?(file) then
333
+ file
334
+ else
335
+ logger.warn("The default #{name} application property file was not found: #{file}.")
336
+ nil
337
+ end
338
+ end
339
+ end
340
+ end
@@ -168,27 +168,21 @@ module Java
168
168
  end
169
169
 
170
170
  class Date
171
- # millisecond-to-day conversion factor
172
- MILLIS_PER_HR = 60 * 60 * 1000
173
- MILLIS_PER_DAY = MILLIS_PER_HR * 24
171
+ # The millisecond-to-day conversion factor.
172
+ MILLIS_PER_DAY = (60 * 60 * 1000) * 24
174
173
 
175
174
  # Converts this Java Date to a Ruby DateTime.
176
175
  #
177
- # caTissue alert - Bug #165: API CPR create date validation is time zone dependent.
178
- # Since Java Date accounts for DST and Ruby DateTime doesn't,
179
- # this method makes the DST adjustment by subtracting a compensatory
180
- # one-hour DST offset from the Java Date time zone offset and using
181
- # that to set the DateTime offset. This ensures that Date
182
- # conversion is idempotent, i.e.
183
- # date.to_ruby_date().to_java_date == date
176
+ # @quirk caTissue Bug #165: API CPR create date validation is time zone dependent.
177
+ # Since Java Date accounts for DST and Ruby DateTime doesn't, this method makes the
178
+ # DST adjustment by subtracting a compensatory one-hour DST offset from the
179
+ # Java Date time zone offset and using that to set the DateTime offset.
180
+ # This ensures that Date conversion is idempotent, i.e.
181
+ # date.to_ruby_date().to_java_date == date
184
182
  #
185
- # However, there can be adverse consequences for an application that assumes
186
- # that the client time zone is the same as the server time zone, as described
187
- # in caTissue Bug #165.
188
- #
189
- # TODO: Revisit {CaRuby::Resource.value_equal?} which must resort to a
190
- # date-as-string comparison, always a bad idea. If that can be fixed, then
191
- # increment/decrement the hour field rather than the offset field.
183
+ # However, there can be adverse consequences for an application that assumes that the
184
+ # client time zone is the same as the server time zone, as described in caTissue
185
+ # Bug #165.
192
186
  #
193
187
  # @return [DateTime] the Ruby date
194
188
  def to_ruby_date
@@ -199,9 +193,13 @@ module Java
199
193
  time = Time.at(secs)
200
194
  # convert UTC timezone millisecond offset to Rational fraction of a day
201
195
  offset_millis = calendar.timeZone.getOffset(calendar.timeInMillis).to_f
202
- offset_days = offset_millis / MILLIS_PER_DAY
203
- offset_fraction = 1 / offset_days
204
- offset = Rational(1, offset_fraction)
196
+ if offset_millis.zero? then
197
+ offset = 0
198
+ else
199
+ offset_days = offset_millis / MILLIS_PER_DAY
200
+ offset_fraction = 1 / offset_days
201
+ offset = Rational(1, offset_fraction)
202
+ end
205
203
  # convert to DateTime
206
204
  DateTime.civil(time.year, time.mon, time.day, time.hour, time.min, time.sec, offset)
207
205
  end
@@ -261,9 +259,13 @@ class Class
261
259
  method_defined?(:java_class)
262
260
  end
263
261
 
264
- # Returns a Ruby class for the given klass. If klass is already a Ruby Class, then returns klass.
265
- # If klass is a String, then returns the Ruby wrapper class for the corresponding Java class name.
266
- # Otherwise, this method returns the Ruby class for the name of the presumed Java klass.
262
+ # Returns the Ruby class for the given class, as follows:
263
+ # * If the given class is already a Ruby class, then return the class.
264
+ # * If the class argument is a Java class or a Java class name, then
265
+ # the Ruby class is the JRuby wrapper for the Java class.
266
+ #
267
+ # @param [Class, String] the class or class name
268
+ # @return [Class] the corresponding Ruby class
267
269
  def self.to_ruby(klass)
268
270
  case klass
269
271
  when Class then klass
@@ -347,10 +349,12 @@ class Class
347
349
  newsym
348
350
  end
349
351
 
350
- # Returns the property descriptor pd introspected or discovered Java read Method.
352
+ # @quirk caCORE java.lang.Boolean is<name> is not introspected as a read method, since the type
353
+ # must be primitive, i.e. `boolean is`<name>.
354
+ #
355
+ # @return [Symbol] the property descriptor pd introspected or discovered Java read Method
351
356
  def property_read_method(pd)
352
357
  return pd.read_method if pd.read_method
353
- # caCORE alert - java.lang.Boolean is<name> is not introspected as a read method, since type must be primitive boolean is<name>
354
358
  return unless pd.get_property_type == Java::JavaLang::Boolean.java_class
355
359
  rdr = java_class.java_method("is#{pd.name.capitalize_first}") rescue nil
356
360
  logger.debug { "Discovered #{qp} #{pd.name} property non-introspected reader method #{rdr.name}." } if rdr
@@ -64,7 +64,7 @@ module CaRuby
64
64
  # collection attributes mentioned above, or to fill in missing values.
65
65
  #
66
66
  # Note that there is an extensive set of attribute defaults defined in
67
- # the CaRuby::ResourceMetadata application domain classes. These defaults
67
+ # the CaRuby::Metadata application domain classes. These defaults
68
68
  # are applied in a migration database save action and need not be set in
69
69
  # a migration shim. For example, if an acceptable default for a +Study+
70
70
  # +active?+ flag is defined in the +Study+ meta-data, then the flag does not
@@ -102,8 +102,8 @@ module CaRuby
102
102
  # for the _attribute_ to modify.
103
103
  #
104
104
  # The migratable reference attributes consist of the non-collection
105
- # {ResourceAttributes#saved_independent_attributes} and
106
- # {ResourceAttributes#unidirectional_dependent_attributes} which don't already have a value.
105
+ # {Attributes#saved_independent_attributes} and
106
+ # {Attributes#unidirectional_dependent_attributes} which don't already have a value.
107
107
  # For each such migratable attribute, if there is a single instance of the attribute
108
108
  # type in the given migrated domain objects, then the attribute is set to that
109
109
  # migrated instance.
@@ -146,7 +146,7 @@ module CaRuby
146
146
  end
147
147
  end
148
148
 
149
- # @param [AttributeMetadata::Filter] the attributes to set
149
+ # @param [Attribute::Filter] the attributes to set
150
150
  # @param row (see #migrate_references)
151
151
  # @param migrated (see #migrate_references)
152
152
  # @param mth_hash (see #migrate_references)
@@ -168,7 +168,7 @@ module CaRuby
168
168
  end
169
169
  end
170
170
 
171
- # @param [AttributeMetadata] attr_md the reference attribute
171
+ # @param [Attribute] attr_md the reference attribute
172
172
  # @param row (see #migrate_references)
173
173
  # @param migrated (see #migrate_references)
174
174
  # @param mth_hash (see #migrate_references)
@@ -38,6 +38,7 @@ module CaRuby
38
38
  # @option opts [String] :bad optional invalid record file
39
39
  # @option opts [Integer] :offset zero-based starting source record number to process (default 0)
40
40
  # @option opts [Boolean] :quiet suppress output messages
41
+ # @option opts [Boolean] :verbose print progress
41
42
  def initialize(opts)
42
43
  @rec_cnt = 0
43
44
  parse_options(opts)
@@ -120,7 +121,7 @@ module CaRuby
120
121
  @create = opts[:create]
121
122
  logger.info("Migration options: #{printable_options(opts).pp_s}.")
122
123
  # flag indicating whether to print a progress monitor
123
- @print_progress = !opts[:quiet]
124
+ @print_progress = opts[:verbose]
124
125
  end
125
126
 
126
127
  def printable_options(opts)
@@ -209,7 +210,7 @@ module CaRuby
209
210
  def add_owners(klass)
210
211
  klass.owners.each do |owner|
211
212
  next if @cls_paths_hash.detect_key { |other| other <= owner } or owner.abstract?
212
- logger.debug { "Migrator adding #{klass.qp} owner #{owner.qp}" }
213
+ logger.debug { "Migrator adding #{klass.qp} owner #{owner}" }
213
214
  @cls_paths_hash[owner] = Array::EMPTY_ARRAY
214
215
  add_owners(owner)
215
216
  end
@@ -297,7 +298,7 @@ module CaRuby
297
298
  attr_mds.each do |attr_md|
298
299
  # the attribute migration method
299
300
  mth = attr_mth_hash[attr_md.to_sym]
300
- # associate the AttributeMetadata => method
301
+ # associate the Attribute => method
301
302
  @attr_md_mgt_mth_map[attr_md] ||= mth if mth
302
303
  end
303
304
  @mgt_mth_hash[klass] = attr_mth_hash
@@ -319,7 +320,9 @@ module CaRuby
319
320
  end
320
321
 
321
322
  # Migrates all rows in the input.
322
- # The required block to this method is described in {#migrate}.
323
+ #
324
+ # @yield (see #migrate)
325
+ # @yieldparam (see #migrate)
323
326
  def migrate_rows # :yields: target
324
327
  # open an CSV output for bad records if the option is set
325
328
  if @bad_rec_file then
@@ -357,8 +360,7 @@ module CaRuby
357
360
  # clear the migration state
358
361
  clear(target)
359
362
  else
360
- # If there is a bad file then warn, reject and continue.
361
- # Otherwise, bail.
363
+ # If there is a bad file then warn, reject and continue. Otherwise, bail.
362
364
  if @bad_rec_file then
363
365
  logger.warn("Migration not performed on record #{rec_no}.")
364
366
  @loader.reject(row)
@@ -366,16 +368,18 @@ module CaRuby
366
368
  raise MigrationError.new("Migration not performed on record #{rec_no}")
367
369
  end
368
370
  end
371
+ # Bump the record count.
369
372
  @rec_cnt += 1
370
373
  end
371
374
  logger.info("Migrated #{mgt_cnt} of #{@rec_cnt} records.")
372
375
  end
373
376
 
374
- # Prints a +\++ progress indicator to stdout.
377
+ # Prints a +\++ progress indicator to stdout if the count parameter is divisible by ten.
375
378
  #
376
379
  # @param [Integer] count the progress step count
377
380
  def print_progress(count)
378
- if count % 72 == 0 then puts "+" else print "+" end
381
+ if count % 720 then puts end
382
+ if count % 10 == 0 then puts "+" else print "+" end
379
383
  end
380
384
 
381
385
  # Clears references to objects allocated for migration of a single row into the given target.
@@ -481,7 +485,7 @@ module CaRuby
481
485
  end
482
486
  end
483
487
 
484
- # Fills the given reference AttributeMetadata path starting at obj.
488
+ # Fills the given reference Attribute path starting at obj.
485
489
  #
486
490
  # @param row (see #create)
487
491
  # @param created (see #create)
@@ -497,7 +501,7 @@ module CaRuby
497
501
  # Sets the given migrated object's reference attribute to a new referenced domain object.
498
502
  #
499
503
  # @param [Resource] obj the domain object being migrated
500
- # @param [AttributeMetadata] attr_md the attribute being migrated
504
+ # @param [Attribute] attr_md the attribute being migrated
501
505
  # @param row (see #create)
502
506
  # @param created (see #create)
503
507
  # @return the new object
@@ -513,7 +517,7 @@ module CaRuby
513
517
  ref
514
518
  end
515
519
 
516
- # Sets the obj migratable AttributeMetadata attr_md to value from the given input row.
520
+ # Sets the obj migratable Attribute attr_md to value from the given input row.
517
521
  def migrate_attribute(obj, attr_md, value, row)
518
522
  # a single value can be used for both a Numeric and a String attribute; coerce the value if necessary
519
523
  # if there is a shim migrate_<attribute> method, then call it on the input value
@@ -554,7 +558,7 @@ module CaRuby
554
558
  end
555
559
 
556
560
  # @param [String] file the migration fields configuration file
557
- # @return [{Class => {AttributeMetadata => Symbol}}] the class => path => header hash
561
+ # @return [{Class => {Attribute => Symbol}}] the class => path => header hash
558
562
  # loaded from the configuration file
559
563
  def load_field_map(file)
560
564
  # load the field mapping config file
@@ -621,7 +625,7 @@ module CaRuby
621
625
  end
622
626
 
623
627
  # @param [String] path_s a period-delimited path string path_s in the form _class_(._attribute_)+
624
- # @return [<AttributeMetadata>] the corresponding attribute metadata path
628
+ # @return [<Attribute>] the corresponding attribute metadata path
625
629
  # @raise [MigrationError] if the path string is malformed or an attribute is not found
626
630
  def create_attribute_path(path_s)
627
631
  names = path_s.split('.')
@@ -632,7 +636,7 @@ module CaRuby
632
636
  if names.empty? then
633
637
  raise MigrationError.new("Attribute entry in migration configuration is not in <class>.<attribute> format: #{value}")
634
638
  end
635
- # build the AttributeMetadata path
639
+ # build the Attribute path
636
640
  path = []
637
641
  names.inject(klass) do |parent, name|
638
642
  attr = name.to_sym
@@ -647,7 +651,7 @@ module CaRuby
647
651
  path << attr_md
648
652
  attr_md.type
649
653
  end
650
- # return the starting class and AttributeMetadata path.
654
+ # return the starting class and Attribute path.
651
655
  # note that the starting class is not necessarily the first path attribute declarer, since the
652
656
  # starting class could be the concrete target class rather than an abstract declarer. this is
653
657
  # important, since the class must be instantiated.
@@ -1,5 +1,5 @@
1
1
  module CaRuby
2
- module ResourceModule
2
+ module Domain
3
3
  # Declares the given classes which will be dynamically modified for migration.
4
4
  # The Java caBIG classes are auto-loaded and wrapped as a CaRuby::Resource, if necessary, and enhanced in the migration shim.
5
5
  def shims(*classes)