caruby-core 2.1.1 → 2.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|