caruby-core 2.1.1 → 2.1.2
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.
- data/Gemfile +1 -0
- data/History.md +5 -1
- data/lib/caruby/database/cache.rb +20 -9
- data/lib/caruby/database/lazy_loader.rb +1 -1
- data/lib/caruby/database/operation.rb +2 -0
- data/lib/caruby/database/persistable.rb +19 -13
- data/lib/caruby/database/persistence_service.rb +14 -38
- data/lib/caruby/database/persistifier.rb +86 -37
- data/lib/caruby/database/reader.rb +87 -87
- data/lib/caruby/database/reader_template_builder.rb +7 -4
- data/lib/caruby/database/sql_executor.rb +32 -15
- data/lib/caruby/database/writer.rb +20 -12
- data/lib/caruby/database/writer_template_builder.rb +10 -6
- data/lib/caruby/database.rb +97 -55
- data/lib/caruby/helpers/coordinate.rb +4 -4
- data/lib/caruby/helpers/person.rb +2 -2
- data/lib/caruby/helpers/properties.rb +4 -4
- data/lib/caruby/helpers/roman.rb +2 -2
- data/lib/caruby/helpers/version.rb +1 -1
- data/lib/caruby/json/serializable.rb +17 -0
- data/lib/caruby/metadata/propertied.rb +8 -1
- data/lib/caruby/metadata/property_characteristics.rb +41 -46
- data/lib/caruby/metadata.rb +1 -2
- data/lib/caruby/migration/migrator.rb +108 -0
- data/lib/caruby/resource.rb +2 -2
- data/lib/caruby/version.rb +1 -1
- data/lib/caruby.rb +0 -2
- data/test/lib/caruby/database/cache_test.rb +1 -3
- metadata +6 -8
- data/lib/caruby/caruby-src.tar.gz +0 -0
- data/lib/caruby/json/deserializer.rb +0 -15
- data/lib/caruby/json/serializer.rb +0 -69
@@ -75,9 +75,9 @@ module CaRuby
|
|
75
75
|
# guard against recursive call back into the same operation
|
76
76
|
# the only allowed recursive call is a dependent create which first creates the owner
|
77
77
|
if recursive_save?(obj, :create) then
|
78
|
-
|
78
|
+
raise DatabaseError.new("Create #{obj.qp} recursively called in context #{print_operations}")
|
79
79
|
elsif obj.identifier then
|
80
|
-
|
80
|
+
raise DatabaseError.new("Create unsuccessful since #{obj.qp} already has identifier #{obj.identifier}")
|
81
81
|
end
|
82
82
|
# create the object
|
83
83
|
perform(:create, obj) { create_object(obj) }
|
@@ -97,7 +97,7 @@ module CaRuby
|
|
97
97
|
def update(obj)
|
98
98
|
# guard against a recursive call back into the same operation.
|
99
99
|
if recursive_save?(obj, :update) then
|
100
|
-
|
100
|
+
raise DatabaseError.new("Update #{obj.qp} recursively called in context #{print_operations}")
|
101
101
|
end
|
102
102
|
# update the object
|
103
103
|
perform(:update, obj) { update_object(obj) }
|
@@ -140,7 +140,7 @@ module CaRuby
|
|
140
140
|
# @raise [ArgumentError] if obj is nil or empty
|
141
141
|
# @raise [DatabaseError] if obj could not be created
|
142
142
|
def ensure_exists(obj)
|
143
|
-
|
143
|
+
raise ArgumentError.new("Database ensure_exists is missing a domain object argument") if obj.nil_or_empty?
|
144
144
|
obj.enumerate { |ref| find(ref, :create) unless ref.identifier }
|
145
145
|
|
146
146
|
end
|
@@ -190,7 +190,7 @@ module CaRuby
|
|
190
190
|
result = create_dependent(owner, obj) if owner
|
191
191
|
result ||= create_from_template(obj)
|
192
192
|
if result.nil? then
|
193
|
-
|
193
|
+
raise DatabaseError.new("#{obj.class.qp} is not creatable in context #{print_operations}")
|
194
194
|
end
|
195
195
|
ensure
|
196
196
|
# since obj now has an id, removed from transients set
|
@@ -242,7 +242,7 @@ module CaRuby
|
|
242
242
|
# @raise [DatabaseError] if obj does not have a proxy
|
243
243
|
def save_with_proxy(obj)
|
244
244
|
proxy = obj.saver_proxy
|
245
|
-
if proxy.nil? then
|
245
|
+
if proxy.nil? then raise DatabaseError.new("#{obj.class.qp} does not have a proxy") end
|
246
246
|
if recursive_save?(proxy, :create) then
|
247
247
|
logger.debug { "Foregoing #{obj.qp} save, since it will be handled by creating the proxy #{proxy}." }
|
248
248
|
return
|
@@ -419,7 +419,7 @@ module CaRuby
|
|
419
419
|
def update_object(obj)
|
420
420
|
# database identifier is required for update
|
421
421
|
if obj.identifier.nil? then
|
422
|
-
|
422
|
+
raise DatabaseError.new("Update target is missing a database identifier: #{obj}")
|
423
423
|
end
|
424
424
|
|
425
425
|
# If this object is proxied, then delegate to the proxy.
|
@@ -435,7 +435,9 @@ module CaRuby
|
|
435
435
|
|
436
436
|
# Update a cascaded dependent by updating the owner.
|
437
437
|
owner = cascaded_dependent_owner(obj)
|
438
|
-
if owner
|
438
|
+
if owner and owner.updatable? then
|
439
|
+
return update_cascaded_dependent(owner, obj)
|
440
|
+
end
|
439
441
|
# Not a cascaded dependent; update using a template.
|
440
442
|
update_from_template(obj)
|
441
443
|
end
|
@@ -460,6 +462,9 @@ module CaRuby
|
|
460
462
|
end
|
461
463
|
|
462
464
|
def update_from_template(obj)
|
465
|
+
unless obj.updatable? then
|
466
|
+
raise DatabaseError.new("#{obj.class.qp} update is not allowed by caTissue")
|
467
|
+
end
|
463
468
|
tmpl = build_update_template(obj)
|
464
469
|
# call the caCORE service with an obj update template
|
465
470
|
save_with_template(obj, tmpl) { |svc| svc.update(tmpl) }
|
@@ -512,7 +517,7 @@ module CaRuby
|
|
512
517
|
# @param [TemplateBuilder] builder the builder to use
|
513
518
|
# @return [Jinx::Resource] the template to use as the save argument
|
514
519
|
def build_save_template(obj, builder)
|
515
|
-
builder.build_template(obj)
|
520
|
+
builder.build_template(obj, @operations.last.autogenerated?)
|
516
521
|
end
|
517
522
|
|
518
523
|
# @param (see #delete)
|
@@ -520,7 +525,7 @@ module CaRuby
|
|
520
525
|
def delete_object(obj)
|
521
526
|
# database identifier is required for delete
|
522
527
|
if obj.identifier.nil? then
|
523
|
-
|
528
|
+
raise DatabaseError.new("Delete target is missing a database identifier: #{obj}")
|
524
529
|
end
|
525
530
|
persistence_service(obj.class).delete_object(obj)
|
526
531
|
end
|
@@ -561,8 +566,7 @@ module CaRuby
|
|
561
566
|
# @param [Jinx::Resource] target the save argument
|
562
567
|
# @param [Jinx::Resource] source the caCORE save result
|
563
568
|
def sync_saved(target, source)
|
564
|
-
|
565
|
-
detoxify(source)
|
569
|
+
detoxify_save_result(source)
|
566
570
|
# sync the save result source with the database
|
567
571
|
sync_saved_result_with_database(source, target)
|
568
572
|
# merge the source into the target
|
@@ -578,6 +582,10 @@ module CaRuby
|
|
578
582
|
save_changed_dependents(target)
|
579
583
|
end
|
580
584
|
|
585
|
+
def detoxify_save_result(source)
|
586
|
+
detoxify(source)
|
587
|
+
end
|
588
|
+
|
581
589
|
# Synchronizes the given save result with the database content.
|
582
590
|
# The source is synchronized by {#sync_save_result}.
|
583
591
|
#
|
@@ -18,7 +18,7 @@ module CaRuby
|
|
18
18
|
def initialize(database)
|
19
19
|
@database = database
|
20
20
|
unless block_given? then
|
21
|
-
|
21
|
+
raise ArgumentError.new("@{qp} is missing the required template copy attribute selector block")
|
22
22
|
end
|
23
23
|
|
24
24
|
# the mergeable attributes filter the given block with exclusions
|
@@ -79,12 +79,13 @@ module CaRuby
|
|
79
79
|
# objects. These uncascaded objects should be ignored by the application but aren't.
|
80
80
|
#
|
81
81
|
# @param [Jinx::Resource] obj the domain object to save
|
82
|
+
# @param [Boolean] autogenerated whether the save is an auto-generated object update
|
82
83
|
# @return [Jinx::Resource] the template to use as the caCORE argument
|
83
84
|
def build_template(obj, autogenerated=false)
|
84
85
|
# set the database operation subject
|
85
86
|
@subject = obj
|
86
87
|
# prepare the object for a store operation
|
87
|
-
ensure_savable(obj)
|
88
|
+
ensure_savable(obj, autogenerated)
|
88
89
|
# copy the cascade hierarchy
|
89
90
|
logger.debug { "Building savable template for #{obj.qp}..." }
|
90
91
|
tmpl = @copy_vstr.visit(obj)
|
@@ -105,8 +106,9 @@ module CaRuby
|
|
105
106
|
# metadata and creates them if necessary.
|
106
107
|
#
|
107
108
|
# @param [Jinx::Resource] obj the object to save
|
109
|
+
# @param [Boolean] autogenerated whether the save is an auto-generated object update
|
108
110
|
# @raise [ValidationError] if the object is invalid
|
109
|
-
def ensure_savable(obj)
|
111
|
+
def ensure_savable(obj, autogenerated)
|
110
112
|
# Ensure that an update is fetched to complete the object state with any missing references.
|
111
113
|
if obj.identifier and not obj.fetched? then
|
112
114
|
logger.debug { "Fetching #{obj} prior to building a save template..." }
|
@@ -123,8 +125,8 @@ module CaRuby
|
|
123
125
|
@database.ensure_exists(prereqs)
|
124
126
|
logger.debug { "Prerequisite references for #{obj.qp} exist: #{prereqs.map { |ref| ref }.to_series}." }
|
125
127
|
end
|
126
|
-
# Verify that the object is complete
|
127
|
-
obj.validate
|
128
|
+
# Verify that the object is complete.
|
129
|
+
obj.validate(autogenerated)
|
128
130
|
end
|
129
131
|
|
130
132
|
# Fetches the given update object savable references on demand.
|
@@ -293,7 +295,7 @@ module CaRuby
|
|
293
295
|
# @param [Jinx::Resource] obj the domain object to save
|
294
296
|
# @return [<Jinx::Resource>] the references which must be created in order to store the object
|
295
297
|
def collect_prerequisites(obj)
|
296
|
-
prereqs =
|
298
|
+
prereqs = Array.new
|
297
299
|
# visit the cascaded attributes
|
298
300
|
@prereq_vstr.visit(obj) do |pref|
|
299
301
|
# Check each mergeable attribute for prerequisites. The mergeable attributes includes
|
@@ -326,6 +328,8 @@ module CaRuby
|
|
326
328
|
end
|
327
329
|
end
|
328
330
|
end
|
331
|
+
# Remove duplicates.
|
332
|
+
prereqs.uniq!
|
329
333
|
prereqs
|
330
334
|
end
|
331
335
|
end
|
data/lib/caruby/database.rb
CHANGED
@@ -36,27 +36,28 @@ module CaRuby
|
|
36
36
|
# The {Writer#save} method creates or updates references as necessary to persist its argument domain object.
|
37
37
|
# It is not necessary to fetch references first or follow dependency ordering rules, which can be
|
38
38
|
# implicit and tortuous in caBIG applications. Build the object you want to persist and call the
|
39
|
-
# store method. {Jinx::Resource} sets reasonable default values, recognizes application dependencies and
|
40
|
-
# around caBIG idiosyncracies to the extent possible.
|
39
|
+
# store method. {Jinx::Resource} sets reasonable default values, recognizes application dependencies and
|
40
|
+
# steers around caBIG idiosyncracies to the extent possible.
|
41
41
|
class Database
|
42
42
|
include Reader, Writer, Persistifier
|
43
43
|
|
44
44
|
# The application and database connection access command line options.
|
45
45
|
ACCESS_OPTS = [
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
]
|
46
|
+
[:user, '-u USER', '--user USER', 'the application login user'],
|
47
|
+
[:password, '-p PSWD', '--password PSWD', 'the application login password'],
|
48
|
+
[:host, '--host HOST', 'the application host name'],
|
49
|
+
[:port, '--port PORT', 'the application port number'],
|
50
|
+
[:classpath, '--classpath PATH', 'the application client classpath'],
|
51
|
+
[:database_host, '--database_host HOST', 'the database host name'],
|
52
|
+
[:database_port, '--database_port PORT', Integer, 'the database port number'],
|
53
|
+
[:database, '--database NAME', 'the database name'],
|
54
|
+
[:database_url, '--database_url URL', 'the database connection URL'],
|
55
|
+
[:database_type, '--database_type TYPE', 'the database type (mysql or oracle)'],
|
56
|
+
[:database_driver, '--database_driver DRIVER', 'the database driver string'],
|
57
|
+
[:database_driver_class, '--database_driver_class CLASS', 'the database driver class name'],
|
58
|
+
[:database_user, '--database_user USER', 'the database login user'],
|
59
|
+
[:database_password, '--database_password PSWD', 'the database login password']
|
60
|
+
]
|
60
61
|
|
61
62
|
attr_reader :operations
|
62
63
|
|
@@ -92,18 +93,14 @@ module CaRuby
|
|
92
93
|
# Database.new(:user => 'perdita', :password => 'changeMe')
|
93
94
|
def initialize(service_name, opts=nil)
|
94
95
|
super()
|
95
|
-
#
|
96
|
+
# The options can be defined in a block.
|
96
97
|
opts ||= yield if block_given?
|
97
|
-
|
98
|
-
Database.import_java_classes
|
99
|
-
# the fetched object cache
|
100
|
-
@defaults = {}
|
101
|
-
if opts.nil? then Jinx.fail(ArgumentError, "Missing required database access properties") end
|
98
|
+
if opts.nil? then raise ArgumentError.new("Missing required database access properties") end
|
102
99
|
@user = Options.get(:user, opts)
|
103
100
|
@password = Options.get(:password, opts)
|
104
101
|
host = Options.get(:host, opts)
|
105
102
|
port = Options.get(:port, opts)
|
106
|
-
# class => service hash
|
103
|
+
# The class => service hash is populated with the default service.
|
107
104
|
@def_persist_svc = PersistenceService.new(service_name, :host => host, :port => port)
|
108
105
|
@persistence_services = [@def_persist_svc].to_set
|
109
106
|
@cls_svc_hash = Hash.new(@def_persist_svc)
|
@@ -112,33 +109,34 @@ module CaRuby
|
|
112
109
|
# the objects for which exists? is unsuccessful in the context of a nested operation
|
113
110
|
@transients = Set.new
|
114
111
|
end
|
112
|
+
|
113
|
+
# @return [Boolean] whether there is an active session
|
114
|
+
def open?
|
115
|
+
!!@session
|
116
|
+
end
|
117
|
+
|
118
|
+
# @return [Boolean] whether this database is not {#open?}
|
119
|
+
def closed?
|
120
|
+
not open?
|
121
|
+
end
|
115
122
|
|
116
123
|
# Calls the block given to this method with this database as an argument, and closes the
|
117
124
|
# database when done.
|
118
125
|
#
|
126
|
+
# @param [String, nil] user the application login user
|
127
|
+
# @param [String, nil] password the application login password
|
119
128
|
# @yield [database] the operation to perform on the database
|
120
129
|
# @yieldparam [Database] database self
|
121
|
-
def open
|
130
|
+
def open(user=nil, password=nil)
|
131
|
+
raise ArgumentError.new("Database open requires an execution block") unless block_given?
|
132
|
+
raise DatabaseError.new("The caRuby application database is already in use.") if open?
|
122
133
|
# reset the execution timers
|
123
134
|
persistence_services.each { |svc| svc.timer.reset }
|
124
|
-
#
|
135
|
+
# Start the session.
|
136
|
+
start_session(user, password)
|
137
|
+
# Call the block and close when done.
|
125
138
|
yield(self) ensure close
|
126
139
|
end
|
127
|
-
|
128
|
-
# Releases database resources. This method should be called when database interaction
|
129
|
-
# is completed.
|
130
|
-
def close
|
131
|
-
return if @session.nil?
|
132
|
-
begin
|
133
|
-
@session.terminate_session
|
134
|
-
rescue Exception => e
|
135
|
-
logger.error("Session termination unsuccessful - #{e.message}")
|
136
|
-
end
|
137
|
-
# clear the cache
|
138
|
-
clear
|
139
|
-
logger.info("Disconnected from application server.")
|
140
|
-
@session = nil
|
141
|
-
end
|
142
140
|
|
143
141
|
# @return [Numeric] the execution time in seconds spent since the last open
|
144
142
|
def execution_time
|
@@ -157,9 +155,8 @@ module CaRuby
|
|
157
155
|
# @return [PersistanceService] the corresponding service
|
158
156
|
def persistence_service(klass)
|
159
157
|
unless Class === klass then
|
160
|
-
|
158
|
+
raise ArgumentError.new("#{self} persistence_service argument is not a Class: {#klass.qp}")
|
161
159
|
end
|
162
|
-
start_session if @session.nil?
|
163
160
|
@def_persist_svc
|
164
161
|
end
|
165
162
|
|
@@ -169,6 +166,15 @@ module CaRuby
|
|
169
166
|
def add_persistence_service(service)
|
170
167
|
@persistence_services << service
|
171
168
|
end
|
169
|
+
|
170
|
+
# Imports the caCORE +ClientSession+ class on demand.
|
171
|
+
def self.const_missing(sym)
|
172
|
+
if sym == :ClientSession then
|
173
|
+
java_import Java::gov.nih.nci.system.comm.client.ClientSession
|
174
|
+
else
|
175
|
+
super
|
176
|
+
end
|
177
|
+
end
|
172
178
|
|
173
179
|
alias :to_s :print_class_and_id
|
174
180
|
|
@@ -178,10 +184,19 @@ module CaRuby
|
|
178
184
|
|
179
185
|
private
|
180
186
|
|
181
|
-
#
|
182
|
-
|
183
|
-
|
184
|
-
|
187
|
+
# Releases database resources. This method should be called when database interaction
|
188
|
+
# is completed.
|
189
|
+
def close
|
190
|
+
return if @session.nil?
|
191
|
+
begin
|
192
|
+
@session.terminate_session
|
193
|
+
rescue Exception => e
|
194
|
+
logger.error("Session termination unsuccessful - #{e.message}")
|
195
|
+
end
|
196
|
+
# clear the cache
|
197
|
+
clear
|
198
|
+
logger.info("Disconnected from application server.")
|
199
|
+
@session = nil
|
185
200
|
end
|
186
201
|
|
187
202
|
# A mergeable autogenerated operation is recursively defined as:
|
@@ -213,22 +228,34 @@ module CaRuby
|
|
213
228
|
# Performs the operation given by the given op symbol on obj by calling the block given to this method.
|
214
229
|
# Lazy loading is suspended during the operation.
|
215
230
|
#
|
216
|
-
# @param [:find, :query, :create, :
|
217
|
-
# @param [
|
231
|
+
# @param [:find, :query, :create, :update, :delete] op the database operation type
|
232
|
+
# @param [Resource] obj the domain object on which the operation is performed
|
218
233
|
# @param opts (#see Operation#initialize)
|
219
234
|
# @yield the database operation block
|
220
235
|
# @return the result of calling the operation block
|
221
|
-
def perform(op, obj, opts=nil)
|
236
|
+
def perform(op, obj, opts=nil, &block)
|
222
237
|
op_s = op.to_s.capitalize_first
|
223
238
|
pa = Options.get(:attribute, opts)
|
224
239
|
attr_s = " #{pa}" if pa
|
225
240
|
ag_s = " autogenerated" if Options.get(:autogenerated, opts)
|
226
241
|
ctxt_s = " in context #{print_operations}" unless @operations.empty?
|
227
242
|
logger.info(">> #{op_s}#{ag_s} #{obj.pp_s(:single_line)}#{attr_s}#{ctxt_s}...")
|
243
|
+
# Clear the error flag.
|
244
|
+
@error = nil
|
245
|
+
# Push the operation on the nested operation stack.
|
228
246
|
@operations.push(Operation.new(op, obj, opts))
|
229
247
|
begin
|
230
248
|
# perform the operation
|
231
|
-
result =
|
249
|
+
result = perform_operation(&block)
|
250
|
+
rescue Exception => e
|
251
|
+
# If the current operation is the immediate cause, then print the
|
252
|
+
# error to the log.
|
253
|
+
if @error.nil? then
|
254
|
+
msg = "Error performing #{op} on #{obj}:\n#{e.message}\n#{obj.dump}\n#{e.backtrace.qp}"
|
255
|
+
logger.error(msg)
|
256
|
+
@error = e
|
257
|
+
end
|
258
|
+
raise e
|
232
259
|
ensure
|
233
260
|
# the operation is done
|
234
261
|
@operations.pop
|
@@ -239,16 +266,31 @@ module CaRuby
|
|
239
266
|
result
|
240
267
|
end
|
241
268
|
|
269
|
+
# Calls the given block with the lazy loader suspended.
|
270
|
+
# The database is opened, if necessary.
|
271
|
+
#
|
272
|
+
# @yield the database operation block
|
273
|
+
# @return the result of calling the operation block
|
274
|
+
def perform_operation(&block)
|
275
|
+
if closed? then
|
276
|
+
open { perform_operation(&block) }
|
277
|
+
else
|
278
|
+
@lazy_loader.suspend { yield }
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
242
282
|
def each_persistence_service(&block)
|
243
283
|
ObjectSpace.each_object(PersistenceService, &block)
|
244
284
|
end
|
245
285
|
|
246
286
|
# Initializes the default application service.
|
247
|
-
def start_session
|
248
|
-
|
249
|
-
|
287
|
+
def start_session(user=nil, password=nil)
|
288
|
+
user ||= @user
|
289
|
+
password ||= @password
|
290
|
+
if user.nil? then raise DatabaseError.new('The caRuby application is missing the login user') end
|
291
|
+
if password.nil? then raise DatabaseError.new('The caRuby application is missing the login password') end
|
250
292
|
@session = ClientSession.instance
|
251
|
-
connect(
|
293
|
+
connect(user, password)
|
252
294
|
end
|
253
295
|
|
254
296
|
# Returns the current database operation stack as a String.
|
@@ -266,7 +308,7 @@ module CaRuby
|
|
266
308
|
begin
|
267
309
|
@session.start_session(user, password)
|
268
310
|
rescue Exception => e
|
269
|
-
logger.error("Login of #{user} unsuccessful - #{e.message}")
|
311
|
+
logger.error("Login of #{user} with password #{password} was unsuccessful - #{e.message}")
|
270
312
|
raise e
|
271
313
|
end
|
272
314
|
logger.info("Connected to application server.")
|
@@ -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
|
-
|
87
|
-
|
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
|
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
|
-
|
92
|
-
|
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
|
93
93
|
cmp = dim <=> odim
|
94
94
|
return cmp unless cmp.zero?
|
95
95
|
end
|
@@ -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
|
-
Jinx.
|
122
|
+
raise Jinx::ValidationError.new("Name is missing both the first and last fields")
|
123
123
|
end
|
124
124
|
if !middle.nil? and first.nil? then
|
125
|
-
Jinx.
|
125
|
+
raise Jinx::ValidationError.new("Name with middle field #{middle} is missing the first field")
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
@@ -66,12 +66,12 @@ module CaRuby
|
|
66
66
|
#
|
67
67
|
# Raises ConfigurationError if file doesn't exist or couldn't be parsed.
|
68
68
|
def load_properties(file)
|
69
|
-
|
69
|
+
raise ConfigurationError.new("Properties file not found: #{File.expand_path(file)}") unless File.exists?(file)
|
70
70
|
properties = {}
|
71
71
|
begin
|
72
|
-
YAML
|
72
|
+
YAML.load_file(file).each { |key, value| properties[key.to_sym] = value }
|
73
73
|
rescue
|
74
|
-
|
74
|
+
raise ConfigurationError.new("Could not read properties file #{file}: " + $!)
|
75
75
|
end
|
76
76
|
# Uncomment the following line to print detail properties.
|
77
77
|
#logger.debug { "#{file} properties:\n#{properties.pp_s}" }
|
@@ -103,7 +103,7 @@ module CaRuby
|
|
103
103
|
# Validates that the required properties exist.
|
104
104
|
def validate_properties
|
105
105
|
@required_properties.each do |key|
|
106
|
-
|
106
|
+
raise ConfigurationError.new("A required #{@application} property was not found: #{key}") unless has_property?(key)
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
data/lib/caruby/helpers/roman.rb
CHANGED
@@ -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
|
9
|
+
else raise ArgumentError.new("#{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
|
21
|
+
if self < 1 or self > 10 then raise ArgumentError.new("#{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
|
-
|
29
|
+
raise ArgumentError.new("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|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'jinx/json/serializable'
|
2
|
+
|
3
|
+
module CaRuby
|
4
|
+
module JSON
|
5
|
+
module Serializable
|
6
|
+
include Jinx::JSON::Serializable
|
7
|
+
|
8
|
+
# This method disables lazy-loading before delegating to Jinx.
|
9
|
+
#
|
10
|
+
# @param [State, Hash, nil] state the JSON state or serialization options
|
11
|
+
# @return [String] the JSON representation of this {Jinx::Resource}
|
12
|
+
def to_json(state=nil)
|
13
|
+
fetched? ? super : do_without_lazy_loader { super }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -168,9 +168,16 @@ module CaRuby
|
|
168
168
|
|
169
169
|
alias :toxic_attributes :unfetched_attributes
|
170
170
|
|
171
|
+
# @quirk JRuby - This method body is copied to the +CaTissue::Metadata+ superclass since
|
172
|
+
# calling super from that class's overloaded +loadable_attributes+ method results in
|
173
|
+
# an infinite loop.
|
174
|
+
#
|
171
175
|
# @return [<Symbol>] the Java attribute non-abstract {#unfetched_attributes}
|
172
176
|
def loadable_attributes
|
173
|
-
|
177
|
+
# A change to this method body must be copied to CaTissue::Metadata; see rubydoc above.
|
178
|
+
@ld_flt ||= unfetched_attributes.compose do |prop|
|
179
|
+
prop.java_property? and not prop.type.abstract? and not prop.transient?
|
180
|
+
end
|
174
181
|
end
|
175
182
|
|
176
183
|
private
|