caruby-core 1.5.5 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. data/Gemfile +9 -0
  2. data/History.md +5 -1
  3. data/lib/caruby.rb +3 -5
  4. data/lib/caruby/caruby-src.tar.gz +0 -0
  5. data/lib/caruby/database.rb +53 -69
  6. data/lib/caruby/database/application_service.rb +25 -0
  7. data/lib/caruby/database/cache.rb +60 -0
  8. data/lib/caruby/database/fetched_matcher.rb +52 -38
  9. data/lib/caruby/database/lazy_loader.rb +4 -4
  10. data/lib/caruby/database/operation.rb +34 -0
  11. data/lib/caruby/database/persistable.rb +171 -86
  12. data/lib/caruby/database/persistence_service.rb +32 -34
  13. data/lib/caruby/database/persistifier.rb +100 -43
  14. data/lib/caruby/database/reader.rb +107 -85
  15. data/lib/caruby/database/reader_template_builder.rb +60 -0
  16. data/lib/caruby/database/saved_matcher.rb +3 -3
  17. data/lib/caruby/database/sql_executor.rb +88 -17
  18. data/lib/caruby/database/writer.rb +213 -177
  19. data/lib/caruby/database/writer_template_builder.rb +334 -0
  20. data/lib/caruby/{util → helpers}/controlled_value.rb +0 -0
  21. data/lib/caruby/{util → helpers}/coordinate.rb +4 -4
  22. data/lib/caruby/{util → helpers}/person.rb +3 -3
  23. data/lib/caruby/{util → helpers}/properties.rb +7 -9
  24. data/lib/caruby/{util → helpers}/roman.rb +2 -2
  25. data/lib/caruby/{util → helpers}/version.rb +1 -1
  26. data/lib/caruby/json/deserializer.rb +2 -2
  27. data/lib/caruby/json/serializer.rb +49 -7
  28. data/lib/caruby/metadata.rb +30 -0
  29. data/lib/caruby/metadata/java_property.rb +21 -0
  30. data/lib/caruby/metadata/propertied.rb +191 -0
  31. data/lib/caruby/metadata/property.rb +22 -0
  32. data/lib/caruby/metadata/property_characteristics.rb +201 -0
  33. data/lib/caruby/migration/migratable.rb +11 -182
  34. data/lib/caruby/rdbi/driver/jdbc.rb +446 -0
  35. data/lib/caruby/resource.rb +20 -823
  36. data/lib/caruby/version.rb +1 -1
  37. data/test/lib/caruby/database/cache_test.rb +54 -0
  38. data/test/lib/caruby/{util → helpers}/controlled_value_test.rb +3 -5
  39. data/test/lib/caruby/{util → helpers}/person_test.rb +4 -6
  40. data/test/lib/caruby/helpers/properties_test.rb +34 -0
  41. data/test/lib/caruby/{util → helpers}/roman_test.rb +2 -3
  42. data/test/lib/caruby/{util → helpers}/version_test.rb +2 -3
  43. data/test/lib/helper.rb +7 -0
  44. metadata +161 -214
  45. data/lib/caruby/cli/application.rb +0 -36
  46. data/lib/caruby/cli/command.rb +0 -202
  47. data/lib/caruby/csv/csv_mapper.rb +0 -159
  48. data/lib/caruby/csv/csvio.rb +0 -203
  49. data/lib/caruby/database/search_template_builder.rb +0 -56
  50. data/lib/caruby/database/store_template_builder.rb +0 -278
  51. data/lib/caruby/domain.rb +0 -193
  52. data/lib/caruby/domain/attribute.rb +0 -584
  53. data/lib/caruby/domain/attributes.rb +0 -628
  54. data/lib/caruby/domain/dependency.rb +0 -225
  55. data/lib/caruby/domain/id_alias.rb +0 -22
  56. data/lib/caruby/domain/importer.rb +0 -183
  57. data/lib/caruby/domain/introspection.rb +0 -176
  58. data/lib/caruby/domain/inverse.rb +0 -172
  59. data/lib/caruby/domain/inversible.rb +0 -90
  60. data/lib/caruby/domain/java_attribute.rb +0 -173
  61. data/lib/caruby/domain/merge.rb +0 -185
  62. data/lib/caruby/domain/metadata.rb +0 -142
  63. data/lib/caruby/domain/mixin.rb +0 -35
  64. data/lib/caruby/domain/properties.rb +0 -95
  65. data/lib/caruby/domain/reference_visitor.rb +0 -428
  66. data/lib/caruby/domain/uniquify.rb +0 -50
  67. data/lib/caruby/import/java.rb +0 -387
  68. data/lib/caruby/migration/migrator.rb +0 -918
  69. data/lib/caruby/migration/resource_module.rb +0 -9
  70. data/lib/caruby/migration/uniquify.rb +0 -17
  71. data/lib/caruby/util/attribute_path.rb +0 -44
  72. data/lib/caruby/util/cache.rb +0 -56
  73. data/lib/caruby/util/class.rb +0 -149
  74. data/lib/caruby/util/collection.rb +0 -1152
  75. data/lib/caruby/util/domain_extent.rb +0 -46
  76. data/lib/caruby/util/file_separator.rb +0 -65
  77. data/lib/caruby/util/inflector.rb +0 -27
  78. data/lib/caruby/util/log.rb +0 -95
  79. data/lib/caruby/util/math.rb +0 -12
  80. data/lib/caruby/util/merge.rb +0 -59
  81. data/lib/caruby/util/module.rb +0 -18
  82. data/lib/caruby/util/options.rb +0 -97
  83. data/lib/caruby/util/partial_order.rb +0 -35
  84. data/lib/caruby/util/pretty_print.rb +0 -204
  85. data/lib/caruby/util/stopwatch.rb +0 -74
  86. data/lib/caruby/util/topological_sync_enumerator.rb +0 -62
  87. data/lib/caruby/util/transitive_closure.rb +0 -55
  88. data/lib/caruby/util/tree.rb +0 -48
  89. data/lib/caruby/util/trie.rb +0 -37
  90. data/lib/caruby/util/uniquifier.rb +0 -30
  91. data/lib/caruby/util/validation.rb +0 -20
  92. data/lib/caruby/util/visitor.rb +0 -365
  93. data/lib/caruby/util/weak_hash.rb +0 -36
  94. data/test/lib/caruby/csv/csv_mapper_test.rb +0 -40
  95. data/test/lib/caruby/csv/csvio_test.rb +0 -69
  96. data/test/lib/caruby/database/persistable_test.rb +0 -92
  97. data/test/lib/caruby/domain/domain_test.rb +0 -112
  98. data/test/lib/caruby/domain/inversible_test.rb +0 -99
  99. data/test/lib/caruby/domain/reference_visitor_test.rb +0 -130
  100. data/test/lib/caruby/import/java_test.rb +0 -80
  101. data/test/lib/caruby/import/mixed_case_test.rb +0 -14
  102. data/test/lib/caruby/migration/test_case.rb +0 -102
  103. data/test/lib/caruby/test_case.rb +0 -230
  104. data/test/lib/caruby/util/cache_test.rb +0 -23
  105. data/test/lib/caruby/util/class_test.rb +0 -61
  106. data/test/lib/caruby/util/collection_test.rb +0 -398
  107. data/test/lib/caruby/util/command_test.rb +0 -55
  108. data/test/lib/caruby/util/domain_extent_test.rb +0 -60
  109. data/test/lib/caruby/util/file_separator_test.rb +0 -30
  110. data/test/lib/caruby/util/inflector_test.rb +0 -12
  111. data/test/lib/caruby/util/lazy_hash_test.rb +0 -34
  112. data/test/lib/caruby/util/merge_test.rb +0 -83
  113. data/test/lib/caruby/util/module_test.rb +0 -25
  114. data/test/lib/caruby/util/options_test.rb +0 -59
  115. data/test/lib/caruby/util/partial_order_test.rb +0 -42
  116. data/test/lib/caruby/util/pretty_print_test.rb +0 -85
  117. data/test/lib/caruby/util/properties_test.rb +0 -50
  118. data/test/lib/caruby/util/stopwatch_test.rb +0 -18
  119. data/test/lib/caruby/util/topological_sync_enumerator_test.rb +0 -69
  120. data/test/lib/caruby/util/transitive_closure_test.rb +0 -67
  121. data/test/lib/caruby/util/tree_test.rb +0 -23
  122. data/test/lib/caruby/util/trie_test.rb +0 -14
  123. data/test/lib/caruby/util/visitor_test.rb +0 -278
  124. data/test/lib/caruby/util/weak_hash_test.rb +0 -45
  125. data/test/lib/examples/clinical_trials/migration/migration_test.rb +0 -58
  126. data/test/lib/examples/clinical_trials/migration/test_case.rb +0 -38
@@ -0,0 +1,334 @@
1
+ require 'jinx/resource/reference_visitor'
2
+ require 'jinx/resource/copy_visitor'
3
+
4
+ module CaRuby
5
+ class Database
6
+ module Writer
7
+ # TemplateBuilder creates a template suitable for a database save operation.
8
+ class TemplateBuilder
9
+ # Creates a new TemplateBuilder for the given database. The attributes to merge into
10
+ # the template are determined by the block given to this initializer, filtered as follows:
11
+ # * If the save operation is a create, then exclude the auto-generated attributes.
12
+ # * If the visited object has an identifier, then include only those attributes
13
+ # which {Domain::Property#cascade_update_to_create?} or have an identifier.
14
+ #
15
+ # @param [Database] database the target database
16
+ # @yield [ref] the required selector block which determines which attributes are copied into the template
17
+ # @yieldparam [Jinx::Resource] ref the domain object to copy
18
+ def initialize(database)
19
+ @database = database
20
+ unless block_given? then
21
+ Jinx.fail(ArgumentError, "@{qp} is missing the required template copy attribute selector block")
22
+ end
23
+
24
+ # the mergeable attributes filter the given block with exclusions
25
+ @mergeable = Proc.new { |ref| mergeable_attributes(ref, yield(ref)) }
26
+ # the savable prerequisite reference visitor
27
+ @prereq_vstr = Jinx::ReferenceVisitor.new(:prune_cycle) { |ref| savable_template_attributes(ref) }
28
+
29
+ # the savable attributes filter the given block with exclusions
30
+ savable = Proc.new { |ref| savable_attributes(ref, yield(ref)) }
31
+ # the domain attributes to copy is determined by the constructor caller
32
+ # @quirk caTissue must copy all of the non-domain attributes rather than just the identifier,
33
+ # since caTissue auto-generated Specimen update requires the parent collection status. This
34
+ # is the only known occurrence of a referenced object required non-identifier attribute.
35
+ # The copy attributes are parameterized by the top-level save target.
36
+ copier = Proc.new do |src|
37
+ tgt = src.copy
38
+ logger.debug { "Store template builder copied #{src.qp} into #{tgt}." }
39
+ copy_proxied_save_references(src, tgt)
40
+ tgt
41
+ end
42
+ # the template copier
43
+ @copy_vstr = Jinx::CopyVisitor.new(:mergeable => savable, :copier => copier) do |ref|
44
+ savable_template_attributes(ref)
45
+ end
46
+ end
47
+
48
+ # Returns a new domain object which serves as the argument for obj create or update.
49
+ #
50
+ # This method copies a portion of the obj object graph to a template object.
51
+ # The template object graph consists of copies of obj object graph which are necessary
52
+ # to store obj. The template object graph contains only those references which are
53
+ # essential to the store operation.
54
+ #
55
+ # @quirk caCORE +caCORE+ expects the store argument to be carefully prepared prior to
56
+ # the create or update. build_savable_template culls the target object with a template
57
+ # which includes only those references which are necessary for the store to succeed.
58
+ # This template builder ensures that mandatory independent references exist. Cascaded
59
+ # dependent references are included in the template but are not created before submission
60
+ # to +caCORE+. These reference attribute distinctions are implicit application rules which
61
+ # are explicated in the +caRuby+ application domain class definition using Metadata
62
+ # methods.
63
+ #
64
+ # @quirk caCORE +caCORE+ create issues an error if a create argument directly or
65
+ # indirectly references a non-cascaded domain object without an identifier, even if the
66
+ # reference is not relevant to the create. The template returned by this method elides
67
+ # all non-essential references.
68
+ #
69
+ # @quirk caCORE application business logic performs unnecessary verification
70
+ # of uncascaded references as if they were a cascaded create. This can result in
71
+ # an obscure ApplicationException. The server.log stack trace indicates the
72
+ # extraneous verification code. For example, +caTissue+ +NewSpecimenBizLogic.validateStorageContainer+
73
+ # is unnecessarily called on a SpecimenCollectionGroup (SCG) update. SCG does not
74
+ # cascade to Specimen, but caTissue considers the SCG update a Specimen create
75
+ # anyway if the SCG references a Specimen without an identifier. The Specimen
76
+ # business logic then raises an exception when it finds a StorageContainer
77
+ # without an identifier in the Specimen object graph. Therefore, an update must
78
+ # build a savable template which prunes the update object graph to exclude uncascaded
79
+ # objects. These uncascaded objects should be ignored by the application but aren't.
80
+ #
81
+ # @param [Jinx::Resource] obj the domain object to save
82
+ # @return [Jinx::Resource] the template to use as the caCORE argument
83
+ def build_template(obj, autogenerated=false)
84
+ # set the database operation subject
85
+ @subject = obj
86
+ # prepare the object for a store operation
87
+ ensure_savable(obj)
88
+ # copy the cascade hierarchy
89
+ logger.debug { "Building savable template for #{obj.qp}..." }
90
+ tmpl = @copy_vstr.visit(obj)
91
+ logger.debug { "Built #{obj.qp} template #{tmpl.qp} by mapping references #{@copy_vstr.matches.qp}" }
92
+ tmpl
93
+ end
94
+
95
+ private
96
+
97
+ # Ensure that the given domain object can be created or updated by setting the identifier for
98
+ # each independent reference in the create template object graph.
99
+ #
100
+ # @quirk caCORE +caCORE+ raises an +ApplicationException+ if an independent reference in the
101
+ # save argument does not have an identifier. The +caCORE+ server log error is as follows:
102
+ # java.lang.IllegalArgumentException: id to load is required for loading
103
+ # The server log stack trace indicates a bizlogic line that offers a clue to the offending
104
+ # reference. caRuby determines which references are independent based on the introspected
105
+ # metadata and creates them if necessary.
106
+ #
107
+ # @param [Jinx::Resource] obj the object to save
108
+ # @raise [ValidationError] if the object is invalid
109
+ def ensure_savable(obj)
110
+ # Ensure that an update is fetched to complete the object state with any missing references.
111
+ if obj.identifier and not obj.fetched? then
112
+ logger.debug { "Fetching #{obj} prior to building a save template..." }
113
+ @database.find(obj)
114
+ end
115
+ # Fill in the savable references for an update.
116
+ fetch_savable_references(obj) if obj.identifier
117
+ # Add defaults, which might introduce prerequisites.
118
+ obj.add_defaults
119
+ # Fetch or create if necessary the prerequisite references.
120
+ prereqs = collect_prerequisites(obj)
121
+ unless prereqs.empty? then
122
+ logger.debug { "Ensuring references for #{obj.qp} exist: #{prereqs.map { |ref| ref.qp }.to_series}..." }
123
+ @database.ensure_exists(prereqs)
124
+ logger.debug { "Prerequisite references for #{obj.qp} exist: #{prereqs.map { |ref| ref }.to_series}." }
125
+ end
126
+ # Verify that the object is complete
127
+ obj.validate
128
+ end
129
+
130
+ # Fetches the given update object savable references on demand.
131
+ #
132
+ # @param [Resource] the object to update
133
+ def fetch_savable_references(obj)
134
+ logger.debug { "Fetching #{obj} savable references on demand..." }
135
+ @database.lazy_loader.enable do
136
+ obj.class.savable_template_attributes.each { |pa| obj.send(pa) }
137
+ end
138
+ end
139
+
140
+ # Returns the attributes to visit in building the template for the given
141
+ # domain object. The visitable attributes consist of the following:
142
+ # * The {Propertied#unproxied_savable_template_attributes} filtered as follows:
143
+ # * If the database operation is a create, then exclude the cascaded attributes.
144
+ # * If the given object has an identifier, then exclude the attributes which
145
+ # have the the :no_cascade_update_to_create flag set.
146
+ # * The {Propertied#proxied_savable_template_attributes} are included if and
147
+ # only if every referenced object has an identifier, and therefore does not
148
+ # need to be proxied.
149
+ #
150
+ # @quirk caTissue caTissue ignores some references, e.g. Participant CPR, and auto-generates
151
+ # the values instead. Therefore, the create template builder excludes these auto-generated
152
+ # attributes. After the create, the auto-generated references are merged into the created
153
+ # object graph and the references are updated if necessary.
154
+ #
155
+ # @param [Jinx::Resource] obj the domain object copied to the update template
156
+ # @return [<Symbol>] the reference attributes to include in the update template
157
+ def savable_template_attributes(obj)
158
+ # The starting set of candidate attributes is the unproxied cascaded references.
159
+ unproxied = savable_attributes(obj, obj.class.unproxied_savable_template_attributes)
160
+ # The proxied attributes to save.
161
+ proxied = savable_proxied_attributes(obj)
162
+ # The combined set of savable attributes
163
+ if proxied.empty? then
164
+ # This is almost always the code path.
165
+ unproxied
166
+ else
167
+ sas = unproxied.to_set.merge(proxied)
168
+ obj.class.domain_attributes.compose { |prop| sas.include?(prop.attribute) }
169
+ end
170
+ end
171
+
172
+ # Filters the given attributes, if necessary, to exclude attributes as follows:
173
+ # * If the save operation is a create, then exclude the
174
+ # {Domain::Property#autogenerated?} attributes.
175
+ #
176
+ # @param [Jinx::Resource] obj the visited domain object
177
+ # @param [Propertied::Filter] the savable attribute filter
178
+ # @return [Propertied::Filter] the composed attribute filter
179
+ def mergeable_attributes(obj, attributes)
180
+ # If this is an update, then there is no filter on the given attributes.
181
+ return attributes if @subject.identifier
182
+ # This is a create: ignore the optional auto-generated attributes.
183
+ mas = obj.mandatory_attributes.to_set
184
+ attributes.compose { |pa| mas.include?(pa.to_sym) or not pa.autogenerated? }
185
+ end
186
+
187
+ # Composes the given attributes, if necessary, to exclude attributes as follows:
188
+ # * If the save operation is a create, then exclude the auto-generated attributes
189
+ # and independent attributes with unsaved references.
190
+ # * If the visited object has an identifier, then include only those attributes
191
+ # which {Domain::Property#cascade_update_to_create?} or have an identifier.
192
+ #
193
+ # @param (see #mergeable_attributes)
194
+ # @return (see #mergeable_attributes)
195
+ def savable_attributes(obj, attributes)
196
+ mgbl = mergeable_attributes(obj, attributes)
197
+ if obj.identifier.nil? then
198
+ mgbl.compose do |prop|
199
+ not bidirectional_unsaved_independent_collection?(obj, prop)
200
+ end
201
+ else
202
+ # The currently visited object is an update: include attributes which
203
+ # either cascade update to create or have saved references.
204
+ mgbl.compose do |prop|
205
+ prop.cascade_update_to_create? or Persistable.saved?(obj.send(prop.attribute))
206
+ end
207
+ end
208
+ end
209
+
210
+ def bidirectional_unsaved_independent_collection?(obj, property)
211
+ property.collection? and
212
+ property.independent? and
213
+ property.bidirectional? and
214
+ Persistable.unsaved?(obj.send(property.attribute))
215
+ end
216
+
217
+ # Returns the proxied attributes to save. A proxied attribute is included only if the proxied
218
+ # dependents have an identifier, since those without an identifer are created separately via
219
+ # the proxy.
220
+ #
221
+ # @param [Jinx::Resource] obj the visited domain object
222
+ # @return [Jinx::AttributeEnumerator] the proxied cascaded attributes with an unsaved reference
223
+ def savable_proxied_attributes(obj)
224
+ # Include a proxied reference only if the proxied dependents have an identifier,
225
+ # since those without an identifer are created separately via the proxy.
226
+ obj.class.proxied_savable_template_attributes.filter do |pa|
227
+ ref = obj.send(pa)
228
+ case ref
229
+ when Enumerable then ref.all? { |dep| dep.identifier }
230
+ when Jinx::Resource then ref.identifier
231
+ end
232
+ end
233
+ end
234
+
235
+ # Copies proxied references as needed.
236
+ #
237
+ # @quirk caTissue even though Specimen save cascades to SpecimenPosition,
238
+ # SpecimenPosition cannot be updated directly. Rather than simply not
239
+ # cascading to the SpecimenPosition, caTissue checks a Specimen save argument
240
+ # to ensure that the SpecimenPosition reflects the current database state
241
+ # rather than the desired cascaded state. Play along with this bizarre
242
+ # mechanism by adding our own bizarre work-around mechanism to copy a
243
+ # proxied reference only if it has an identifier. This works only because
244
+ # another work-around in the #{Writer} updates proxied
245
+ # references via the proxy create before building the update template.
246
+ def copy_proxied_save_references(obj, template)
247
+ return unless obj.identifier
248
+ obj.class.proxied_savable_template_attributes.each do |pa|
249
+ # the proxy source
250
+ ref = obj.send(pa)
251
+ case ref
252
+ when Enumerable then
253
+ # recurse on the source collection
254
+ coll = template.send(pa)
255
+ ref.each do |dep|
256
+ copy = copy_proxied_save_reference(obj, pa, template, dep)
257
+ coll << copy if copy
258
+ end
259
+ when Jinx::Resource then
260
+ # copy the source
261
+ copy = copy_proxied_save_reference(obj, pa, template, ref)
262
+ # set the attribute to the copy
263
+ template.set_property_value(pa, copy) if copy
264
+ end
265
+ end
266
+ end
267
+
268
+ # Copies a proxied reference.
269
+ #
270
+ # @return [Jinx::Resource, nil] the copy, or nil if no copy is made
271
+ def copy_proxied_save_reference(obj, attribute, template, proxied)
272
+ # only copy an existing proxied
273
+ return unless proxied.identifier
274
+ # the proxied attribute => value hash
275
+ vh = proxied.value_hash
276
+ # map references to either the copied owner or a new copy of the reference
277
+ tvh = vh.transform_value { |v| Jinx::Resource === v ? (v == obj ? template : v.copy) : v }
278
+ # the copy with the adjusted values
279
+ copy = proxied.class.new.merge_attributes(tvh)
280
+ logger.debug { "Created #{obj.qp} proxied #{attribute} save template copy #{proxied.pp_s}." }
281
+ copy
282
+ end
283
+
284
+ # A directly or indirectly referenced object is a target object save prerequisite if
285
+ # none of the following is true:
286
+ # * it is cascaded and will be created when the target is saved
287
+ # * it is a bidirectional unsaved independent collection reference
288
+ # * it is the target object
289
+ # * it has an identifier
290
+ # * it is in an immediate or recursive dependent of the target object
291
+ # * the current save operation is in the context of creating the referenced object
292
+ #
293
+ # @param [Jinx::Resource] obj the domain object to save
294
+ # @return [<Jinx::Resource>] the references which must be created in order to store the object
295
+ def collect_prerequisites(obj)
296
+ prereqs = Set.new
297
+ # visit the cascaded attributes
298
+ @prereq_vstr.visit(obj) do |pref|
299
+ # Check each mergeable attribute for prerequisites. The mergeable attributes includes
300
+ # both cascaded and independent attributes. The selection block filters for independent
301
+ # domain objects which don't have an identifier.
302
+ @mergeable.call(pref).each_pair do |ma, mp|
303
+ # Cascaded attributes are not prerequisite, since they are created when the owner is
304
+ # created. The exception is if the owner will be updated but the dependent will not
305
+ # be created upon owner update and the dependent does not reference the owner.
306
+ # In that case, create the dependent before saving the owner. This ensures that the
307
+ # owner saves the reference to the new dependent.
308
+ #
309
+ # Note that each non-prerequisite cascaded reference is still visited in order to ensure
310
+ # that each independent object referenced by a cascaded reference is recognized as a
311
+ # candidate prerequisite.
312
+ if mp.cascaded? then
313
+ unless pref.identifier.nil? or mp.inverse_property or mp.cascade_update_to_create? then
314
+ pref.send(ma).enumerate do |mref|
315
+ prereqs << mref if mref != obj and mref.identifier.nil?
316
+ end
317
+ end
318
+ elsif not bidirectional_unsaved_independent_collection?(pref, mp) then
319
+ # add qualified prerequisite attribute references
320
+ pref.send(ma).enumerate do |mref|
321
+ # Add each unsaved reference that is not a direct or indirect dependent.
322
+ unless mref == obj or mref.identifier or mref.owner_ancestor?(obj) then
323
+ prereqs << mref
324
+ end
325
+ end
326
+ end
327
+ end
328
+ end
329
+ prereqs
330
+ end
331
+ end
332
+ end
333
+ end
334
+ end
File without changes
@@ -83,13 +83,13 @@ class Coordinate < Array
83
83
  # @raise [TypeError] if other is not a Coordinate
84
84
  def <=>(other)
85
85
  return 0 if equal?(other)
86
- raise TypeError.new("Can't compare #{self} with #{other} since it is not a Coordinate") unless Coordinate === other
87
- raise ArgumentError.new("Can't compare #{self} with #{other} since it has a different dimension count") unless size == other.size
86
+ Jinx.fail(TypeError, "Can't compare #{self} with #{other} since it is not a Coordinate") unless Coordinate === other
87
+ Jinx.fail(ArgumentError, "Can't compare #{self} with #{other} since it has a different dimension count") unless size == other.size
88
88
  REXML::SyncEnumerator.new(self.reverse, other.reverse).each_with_index do |pair, index|
89
89
  dim = pair.first
90
90
  odim = pair.last
91
- raise ArgumentError.new("Can't compare #{self} with missing dimension #{index} to #{other}") unless dim
92
- raise ArgumentError.new("Can't compare #{self} to #{other} with missing dimension #{index}") unless odim
91
+ Jinx.fail(ArgumentError, "Can't compare #{self} with missing dimension #{index} to #{other}") unless dim
92
+ Jinx.fail(ArgumentError, "Can't compare #{self} to #{other} with missing dimension #{index}") unless odim
93
93
  cmp = dim <=> odim
94
94
  return cmp unless cmp.zero?
95
95
  end
@@ -1,4 +1,4 @@
1
- require 'caruby/util/validation'
1
+ require 'jinx/helpers/validation'
2
2
 
3
3
  # Mix-in for standard Person attributes.
4
4
  module CaRuby
@@ -119,10 +119,10 @@ module CaRuby
119
119
  # or if there is a middle name but no first name
120
120
  def validate
121
121
  if last.nil? and first.nil? then
122
- raise ValidationError.new("Name is missing both the first and last fields")
122
+ Jinx.fail(Jinx::ValidationError, "Name is missing both the first and last fields")
123
123
  end
124
124
  if !middle.nil? and first.nil? then
125
- raise ValidationError.new("Name with middle field #{middle} is missing the first field")
125
+ Jinx.fail(Jinx::ValidationError, "Name with middle field #{middle} is missing the first field")
126
126
  end
127
127
  end
128
128
 
@@ -1,9 +1,8 @@
1
1
  require 'yaml'
2
2
  require 'set'
3
- require 'caruby/util/log'
4
- require 'caruby/util/pretty_print'
5
- require 'caruby/util/collection'
6
- require 'caruby/util/merge'
3
+ require 'jinx/helpers/pretty_print'
4
+ require 'jinx/helpers/collection'
5
+ require 'jinx/helpers/merge'
7
6
 
8
7
  module CaRuby
9
8
  # Exception raised if a configuration property is missing or invalid.
@@ -67,15 +66,14 @@ module CaRuby
67
66
  #
68
67
  # Raises ConfigurationError if file doesn't exist or couldn't be parsed.
69
68
  def load_properties(file)
70
- raise ConfigurationError.new("Properties file not found: #{File.expand_path(file)}") unless File.exists?(file)
71
- logger.debug { "Loading properties file #{file}..." }
69
+ Jinx.fail(ConfigurationError, "Properties file not found: #{File.expand_path(file)}") unless File.exists?(file)
72
70
  properties = {}
73
71
  begin
74
72
  YAML::load_file(file).each { |key, value| properties[key.to_sym] = value }
75
73
  rescue
76
- raise ConfigurationError.new("Could not read properties file #{file}: " + $!)
74
+ Jinx.fail(ConfigurationError, "Could not read properties file #{file}: " + $!)
77
75
  end
78
- # Uncomment the following line to print detail properties.
76
+ # Uncomment the following line to print detail properties.
79
77
  #logger.debug { "#{file} properties:\n#{properties.pp_s}" }
80
78
  # parse comma-delimited string values of array properties into arrays
81
79
  @array_properties.each do |key|
@@ -105,7 +103,7 @@ module CaRuby
105
103
  # Validates that the required properties exist.
106
104
  def validate_properties
107
105
  @required_properties.each do |key|
108
- raise CaRuby::ConfigurationError.new("A required #{@application} property was not found: #{key}") unless has_property?(key)
106
+ Jinx.fail(ConfigurationError, "A required #{@application} property was not found: #{key}") unless has_property?(key)
109
107
  end
110
108
  end
111
109
  end
@@ -6,7 +6,7 @@ class String
6
6
  when /^(I{0,3})$/ then $1.size
7
7
  when /^(I{0,3})(V|X)$/ then ROMAN_UNITS[$2] - $1.size
8
8
  when /^(V)(I{0,3})$/ then ROMAN_UNITS[$1] + $2.size
9
- else raise ArgumentError.new("#{self} is not a roman numeral in the range I-X")
9
+ else Jinx.fail(ArgumentError, "#{self} is not a roman numeral in the range I-X")
10
10
  end
11
11
  end
12
12
 
@@ -18,7 +18,7 @@ end
18
18
  class Integer
19
19
  # @return [String] the roman numeral equivalent of this integer
20
20
  def to_roman
21
- if self < 1 or self > 10 then raise ArgumentError.new("#{self} cannot be converted to a roman numeral in the range I-X")
21
+ if self < 1 or self > 10 then Jinx.fail(ArgumentError, "#{self} cannot be converted to a roman numeral in the range I-X")
22
22
  elsif self < 4 then 'I' * self
23
23
  elsif self < 6 then ('I' * (5 - self)) + 'V'
24
24
  elsif self < 9 then 'V' + ('I' * (self - 5))
@@ -26,7 +26,7 @@ class Version < Array
26
26
  # Version.new(1, 1, beta) > beta #=> true
27
27
  def <=>(other)
28
28
  return 0 if equal?(other)
29
- raise ArgumentError.new("Comparand is not a #{self.class}: #{other}") unless self.class === other
29
+ Jinx.fail(ArgumentError, "Comparand is not a #{self.class}: #{other}") unless self.class === other
30
30
  return -1 if other.predecessor == self
31
31
  return 1 unless predecessor.nil? or predecessor < other
32
32
  each_with_index do |component, index|
@@ -2,10 +2,10 @@ require 'json'
2
2
 
3
3
  module CaRuby
4
4
  module JSON
5
- # JSON => {Resource} deserializer.
5
+ # JSON => {Jinx::Resource} deserializer.
6
6
  module Deserializer
7
7
  # @param [String] json the JSON to deserialize
8
- # @return [Resource] the deserialized object
8
+ # @return [Jinx::Resource] the deserialized object
9
9
  def json_create(json)
10
10
  # Make the new object from the json data attribute => value hash.
11
11
  new(json['data'])