caruby-core 1.4.9 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
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)