lafcadio 0.5.2 → 0.6.0

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.
@@ -105,18 +105,18 @@ module Lafcadio
105
105
  ASC = 1
106
106
  DESC = 2
107
107
 
108
- attr_reader :object_type, :condition
108
+ attr_reader :domain_class, :condition
109
109
  attr_accessor :order_by, :order_by_order, :limit
110
110
 
111
- def initialize(object_type, pk_idOrCondition = nil)
112
- @object_type = object_type
111
+ def initialize(domain_class, pk_idOrCondition = nil)
112
+ @domain_class = domain_class
113
113
  ( @condition, @order_by, @limit ) = [ nil, nil, nil ]
114
114
  if pk_idOrCondition
115
115
  if pk_idOrCondition.class <= Condition
116
116
  @condition = pk_idOrCondition
117
117
  else
118
- @condition = Query::Equals.new( object_type.sql_primary_key_name,
119
- pk_idOrCondition, object_type )
118
+ @condition = Query::Equals.new( 'pk_id', pk_idOrCondition,
119
+ domain_class )
120
120
  end
121
121
  end
122
122
  @order_by_order = ASC
@@ -125,7 +125,7 @@ module Lafcadio
125
125
  def and( &action ); compound( CompoundCondition::AND, action ); end
126
126
 
127
127
  def compound( comp_type, action )
128
- rquery = Query.infer( @object_type ) { |dobj| action.call( dobj ) }
128
+ rquery = Query.infer( @domain_class ) { |dobj| action.call( dobj ) }
129
129
  comp_cond = Query::CompoundCondition.new( @condition, rquery.condition,
130
130
  comp_type )
131
131
  comp_cond.query
@@ -151,12 +151,12 @@ module Lafcadio
151
151
  end
152
152
  end
153
153
 
154
- def sql_primary_key_field(object_type)
155
- "#{ object_type.table_name }.#{ object_type.sql_primary_key_name }"
154
+ def sql_primary_key_field(domain_class)
155
+ "#{ domain_class.table_name }.#{ domain_class.sql_primary_key_name }"
156
156
  end
157
157
 
158
158
  def tables
159
- concrete_classes = object_type.self_and_concrete_superclasses.reverse
159
+ concrete_classes = domain_class.self_and_concrete_superclasses.reverse
160
160
  table_names = concrete_classes.collect { |domain_class|
161
161
  domain_class.table_name
162
162
  }
@@ -172,7 +172,7 @@ module Lafcadio
172
172
  end
173
173
 
174
174
  def where_clause
175
- concrete_classes = object_type.self_and_concrete_superclasses.reverse
175
+ concrete_classes = domain_class.self_and_concrete_superclasses.reverse
176
176
  where_clauses = []
177
177
  concrete_classes.each_with_index { |domain_class, i|
178
178
  if i < concrete_classes.size - 1
@@ -191,18 +191,18 @@ module Lafcadio
191
191
  Object
192
192
  end
193
193
 
194
- attr_reader :object_type
194
+ attr_reader :domain_class
195
195
 
196
- def initialize(fieldName, searchTerm, object_type)
196
+ def initialize(fieldName, searchTerm, domain_class)
197
197
  @fieldName = fieldName
198
198
  @searchTerm = searchTerm
199
199
  unless @searchTerm.class <= self.class.search_term_type
200
200
  raise "Incorrect searchTerm type #{ searchTerm.class }"
201
201
  end
202
- @object_type = object_type
203
- if @object_type
204
- unless @object_type <= DomainObject
205
- raise "Incorrect object type #{ @object_type.to_s }"
202
+ @domain_class = domain_class
203
+ if @domain_class
204
+ unless @domain_class <= DomainObject
205
+ raise "Incorrect object type #{ @domain_class.to_s }"
206
206
  end
207
207
  end
208
208
  end
@@ -210,32 +210,28 @@ module Lafcadio
210
210
  def db_field_name; get_field.db_table_and_field_name; end
211
211
 
212
212
  def get_field
213
- anObjectType = @object_type
213
+ a_domain_class = @domain_class
214
214
  field = nil
215
- while (anObjectType < DomainObject || anObjectType < DomainObject) &&
216
- !field
217
- field = anObjectType.get_class_field( @fieldName ) ||
218
- anObjectType.get_class_field_by_db_name( @fieldName )
219
- anObjectType = anObjectType.superclass
215
+ while ( a_domain_class < DomainObject ) && !field
216
+ field = a_domain_class.get_class_field( @fieldName )
217
+ a_domain_class = a_domain_class.superclass
220
218
  end
221
219
  if field
222
220
  field
223
221
  else
224
222
  errStr = "Couldn't find field \"#{ @fieldName }\" in " +
225
- "#{ @object_type } domain class"
223
+ "#{ @domain_class } domain class"
226
224
  raise( MissingError, errStr, caller )
227
225
  end
228
226
  end
229
227
 
230
- def query; Query.new( @object_type, self ); end
228
+ def query; Query.new( @domain_class, self ); end
231
229
 
232
230
  def not
233
231
  Query::Not.new( self )
234
232
  end
235
233
 
236
- def primary_key_field?
237
- [ @object_type.sql_primary_key_name, 'pk_id' ].include?( @fieldName )
238
- end
234
+ def primary_key_field?; 'pk_id' == @fieldName; end
239
235
 
240
236
  def to_condition; self; end
241
237
  end
@@ -260,8 +256,8 @@ module Lafcadio
260
256
  GREATER_THAN => Proc.new { |d1, d2| d1 > d2 }
261
257
  }
262
258
 
263
- def initialize(fieldName, searchTerm, object_type, compareType)
264
- super fieldName, searchTerm, object_type
259
+ def initialize(fieldName, searchTerm, domain_class, compareType)
260
+ super fieldName, searchTerm, domain_class
265
261
  @compareType = compareType
266
262
  end
267
263
 
@@ -298,7 +294,7 @@ module Lafcadio
298
294
  @compoundType = AND
299
295
  end
300
296
  @conditions = conditions
301
- @object_type = conditions[0].object_type
297
+ @domain_class = conditions[0].domain_class
302
298
  end
303
299
 
304
300
  def object_meets(anObj)
@@ -344,7 +340,16 @@ module Lafcadio
344
340
  if @searchTerm.class <= ObjectField
345
341
  @searchTerm.db_table_and_field_name
346
342
  else
347
- field.value_for_sql(@searchTerm).to_s
343
+ begin
344
+ field.value_for_sql( @searchTerm ).to_s
345
+ rescue DomainObjectInitError
346
+ raise(
347
+ ArgumentError,
348
+ "Can't query using an uncommitted domain object as a search " +
349
+ "term.",
350
+ caller
351
+ )
352
+ end
348
353
  end
349
354
  end
350
355
 
@@ -382,6 +387,19 @@ module Lafcadio
382
387
  "#{ db_field_name } in (#{ @searchTerm.join(', ') })"
383
388
  end
384
389
  end
390
+
391
+ class Include < CompoundCondition
392
+ def initialize( field_name, search_term, domain_class )
393
+ begin_cond = Like.new( field_name, search_term + ',', domain_class,
394
+ Like::POST_ONLY )
395
+ mid_cond = Like.new( field_name, ',' + search_term + ',',
396
+ domain_class )
397
+ end_cond = Like.new( field_name, ',' + search_term, domain_class,
398
+ Like::PRE_ONLY )
399
+ only_cond = Equals.new( field_name, search_term, domain_class )
400
+ super( begin_cond, mid_cond, end_cond, only_cond, OR )
401
+ end
402
+ end
385
403
 
386
404
  class Inferrer #:nodoc:
387
405
  def initialize( domain_class, &action )
@@ -401,8 +419,8 @@ module Lafcadio
401
419
  POST_ONLY = 3
402
420
 
403
421
  def initialize(
404
- fieldName, searchTerm, object_type, matchType = PRE_AND_POST)
405
- super fieldName, searchTerm, object_type
422
+ fieldName, searchTerm, domain_class, matchType = PRE_AND_POST)
423
+ super fieldName, searchTerm, domain_class
406
424
  @matchType = matchType
407
425
  end
408
426
 
@@ -441,36 +459,11 @@ module Lafcadio
441
459
  end
442
460
  end
443
461
 
444
- class Link < Condition #:nodoc:
445
- def initialize( fieldName, searchTerm, object_type )
446
- if searchTerm.pk_id.nil?
447
- raise ArgumentError,
448
- "Can't query using an uncommitted domain object as a search term",
449
- caller
450
- else
451
- super( fieldName, searchTerm, object_type )
452
- end
453
- end
454
-
455
- def self.search_term_type
456
- DomainObject
457
- end
458
-
459
- def object_meets(anObj)
460
- value = anObj.send @fieldName
461
- value ? value.pk_id == @searchTerm.pk_id : false
462
- end
463
-
464
- def to_sql
465
- "#{ db_field_name } = #{ @searchTerm.pk_id }"
466
- end
467
- end
468
-
469
462
  class Max < Query #:nodoc:
470
463
  attr_reader :field_name
471
464
 
472
- def initialize( object_type, field_name = 'pk_id' )
473
- super( object_type )
465
+ def initialize( domain_class, field_name = 'pk_id' )
466
+ super( domain_class )
474
467
  @field_name = field_name
475
468
  end
476
469
 
@@ -483,7 +476,7 @@ module Lafcadio
483
476
  end
484
477
 
485
478
  def fields
486
- "max(#{ @object_type.get_field( @field_name ).db_field_name })"
479
+ "max(#{ @domain_class.get_field( @field_name ).db_field_name })"
487
480
  end
488
481
  end
489
482
 
@@ -496,7 +489,7 @@ module Lafcadio
496
489
  !@unCondition.object_meets(obj)
497
490
  end
498
491
 
499
- def object_type; @unCondition.object_type; end
492
+ def domain_class; @unCondition.domain_class; end
500
493
 
501
494
  def to_sql
502
495
  "!(#{ @unCondition.to_sql })"
@@ -517,10 +510,10 @@ module Lafcadio
517
510
  def initialize( domainObjectImpostor, class_field_or_name )
518
511
  @domainObjectImpostor = domainObjectImpostor
519
512
  if class_field_or_name == 'pk_id'
520
- @db_field_name = 'pk_id'
513
+ @field_name = 'pk_id'
521
514
  else
522
515
  @class_field = class_field_or_name
523
- @db_field_name = class_field_or_name.db_field_name
516
+ @field_name = class_field_or_name.name
524
517
  end
525
518
  end
526
519
 
@@ -535,12 +528,12 @@ module Lafcadio
535
528
 
536
529
  def register_compare_condition( compareStr, searchTerm)
537
530
  compareVal = ObjectFieldImpostor.comparators[compareStr]
538
- Compare.new( @db_field_name, searchTerm,
531
+ Compare.new( @field_name, searchTerm,
539
532
  @domainObjectImpostor.domain_class, compareVal )
540
533
  end
541
534
 
542
535
  def equals( searchTerm )
543
- Equals.new( @db_field_name, field_or_field_name( searchTerm ),
536
+ Equals.new( @field_name, field_or_field_name( searchTerm ),
544
537
  @domainObjectImpostor.domain_class )
545
538
  end
546
539
 
@@ -552,29 +545,45 @@ module Lafcadio
552
545
  end
553
546
  end
554
547
 
548
+ def include?( search_term )
549
+ if @class_field.instance_of?( TextListField )
550
+ Include.new( @field_name, search_term,
551
+ @domainObjectImpostor.domain_class )
552
+ else
553
+ raise ArgumentError
554
+ end
555
+ end
556
+
555
557
  def like( regexp )
556
- if regexp.source =~ /^\^(.*)/
557
- searchTerm = $1
558
- matchType = Query::Like::POST_ONLY
559
- elsif regexp.source =~ /(.*)\$$/
560
- searchTerm = $1
561
- matchType = Query::Like::PRE_ONLY
558
+ if regexp.is_a?( Regexp )
559
+ if regexp.source =~ /^\^(.*)/
560
+ searchTerm = $1
561
+ matchType = Query::Like::POST_ONLY
562
+ elsif regexp.source =~ /(.*)\$$/
563
+ searchTerm = $1
564
+ matchType = Query::Like::PRE_ONLY
565
+ else
566
+ searchTerm = regexp.source
567
+ matchType = Query::Like::PRE_AND_POST
568
+ end
569
+ Query::Like.new( @field_name, searchTerm,
570
+ @domainObjectImpostor.domain_class, matchType )
562
571
  else
563
- searchTerm = regexp.source
564
- matchType = Query::Like::PRE_AND_POST
572
+ raise(
573
+ ArgumentError, "#{ @field_name }#like needs to receive a Regexp",
574
+ caller
575
+ )
565
576
  end
566
- Query::Like.new( @db_field_name, searchTerm,
567
- @domainObjectImpostor.domain_class, matchType )
568
577
  end
569
578
 
570
579
  def in( *searchTerms )
571
- Query::In.new( @db_field_name, searchTerms,
580
+ Query::In.new( @field_name, searchTerms,
572
581
  @domainObjectImpostor.domain_class )
573
582
  end
574
583
 
575
584
  def to_condition
576
585
  if @class_field.instance_of?( BooleanField )
577
- Query::Equals.new( @db_field_name, true,
586
+ Query::Equals.new( @field_name, true,
578
587
  @domainObjectImpostor.domain_class )
579
588
  else
580
589
  raise
@@ -16,7 +16,6 @@ module Lafcadio
16
16
  definitionTerms << field.db_field_name
17
17
  definitionTerms << type_clause( field )
18
18
  definitionTerms << 'not null' if field.not_null
19
- definitionTerms << 'unique' if field.unique
20
19
  definitionTerms.join( ' ' )
21
20
  end
22
21
 
data/lib/lafcadio/test.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  require 'lafcadio/depend'
2
2
  require 'lafcadio/mock'
3
3
  require 'lafcadio/util'
4
+ require 'test/unit'
4
5
 
5
6
  # A test case that sets up a number of mock services. In writing an application
6
7
  # that uses Lafcadio you may find it convenient to inherit from this class.
7
- class LafcadioTestCase < RUNIT::TestCase
8
+ class LafcadioTestCase < Test::Unit::TestCase
8
9
  include Lafcadio
9
10
 
10
11
  def setup
@@ -14,4 +15,6 @@ class LafcadioTestCase < RUNIT::TestCase
14
15
  ObjectStore.set_object_store @mockObjectStore
15
16
  LafcadioConfig.set_filename 'lafcadio/test/testConfig.dat'
16
17
  end
18
+
19
+ def default_test; end
17
20
  end
@@ -5,9 +5,7 @@ dbhost:localhost
5
5
  adminEmail:john.doe@email.com
6
6
  siteName:Site Name
7
7
  url:http://test.url
8
- classpath:lafcadio/
9
8
  logdir:../test/testOutput/
10
- domainDirs:../test/mock/domain/
11
9
  domainFiles:../test/mock/domain.rb
12
10
  logSql:n
13
11
  classDefinitionDir:../test/testData
@@ -0,0 +1,13 @@
1
+ dbuser:test
2
+ dbpassword:password
3
+ dbname:test
4
+ dbhost:localhost
5
+ adminEmail:john.doe@email.com
6
+ siteName:Site Name
7
+ url:http://test.url
8
+ classpath:lafcadio/
9
+ logdir:../test/testOutput/
10
+ domainDirs:../test/mock/domain/
11
+ domainFiles:../test/mock/domain.rb
12
+ logSql:n
13
+ classDefinitionDir:../test/testData
data/lib/lafcadio/util.rb CHANGED
@@ -1,43 +1,7 @@
1
1
  require 'delegate'
2
2
  require 'singleton'
3
3
 
4
- class Array
5
- # If this array has one element, returns that element; otherwise, raises an
6
- # error.
7
- def only
8
- if size != 1
9
- raise "Expected single-value Array but Array has #{ size } members"
10
- else
11
- first
12
- end
13
- end
14
- end
15
-
16
- class Class < Module
17
- # Given a String, returns a class object by the same name.
18
- def self.get_class(className)
19
- theClass = nil
20
- ObjectSpace.each_object(Class) { |aClass|
21
- theClass = aClass if aClass.name == className
22
- }
23
- if theClass
24
- theClass
25
- else
26
- raise( Lafcadio::MissingError, "Couldn't find class \"#{ className }\"",
27
- caller )
28
- end
29
- end
30
-
31
- # Returns the name of <tt>aClass</tt> itself, stripping off the names of any
32
- # containing modules or outer classes.
33
- def bare_name
34
- name =~ /::/
35
- $' || name
36
- end
37
- end
38
-
39
4
  module Lafcadio
40
-
41
5
  # The Context is a singleton object that manages ContextualServices. Each
42
6
  # ContextualService is a service that connects in some way to external
43
7
  # resources: ObjectStore connects to the database; Emailer connects to SMTP,
@@ -100,6 +64,8 @@ module Lafcadio
100
64
  #
101
65
  # For example: ObjectStore.getObjectStore
102
66
  class ContextualService
67
+ def self.flush; Context.instance.set_resource( self, nil ); end
68
+
103
69
  def self.method_missing( methodId, *args )
104
70
  methodName = methodId.id2name
105
71
  if methodName =~ /^get_(.*)/ || methodName =~ /^set_(.*)/
@@ -348,32 +314,6 @@ module Lafcadio
348
314
  end
349
315
  end
350
316
 
351
- class Numeric
352
- # Returns a string that represents the numbeer to <tt>precision</tt> decimal
353
- # places, rounding down if necessary. If <tt>padDecimals</tt> is set to
354
- # <tt>false</tt> and the number rounds to a whole number, there will be no
355
- # decimals shown.
356
- #
357
- # (24.55).precision_format( 3 ) -> "24.550"
358
- # (24.55).precision_format( 0 ) -> "24"
359
- # 100.precision_format( 2, false ) -> "100"
360
- def precision_format(precision, padDecimals = true)
361
- str = floor.to_s
362
- if precision > 0
363
- decimal = self - self.floor
364
- decimalStr =(decimal * 10 ** precision).floor.to_s
365
- if decimalStr.size < precision
366
- decimalStr += "0" *(precision - decimalStr.size)
367
- end
368
- if padDecimals || decimalStr =~ /[123456789]/
369
- str += "."
370
- str += decimalStr
371
- end
372
- end
373
- str
374
- end
375
- end
376
-
377
317
  class String
378
318
  # Returns the underscored version of a camel-case string.
379
319
  def camel_case_to_underscore
@@ -410,46 +350,6 @@ class String
410
350
  newString
411
351
  end
412
352
 
413
- # Increments a filename. If the filename ends with a number, it increments
414
- # that number; otherwise it appends a "_1" after the filename but before the
415
- # file extension.
416
- #
417
- # "john.jpg".increment_filename -> "john_1.jpg"
418
- # "john_1.jpg".increment_filename -> "john_2.jpg"
419
- # "john_2.jpg".increment_filename -> "john_3.jpg"
420
- def increment_filename
421
- filename = self.clone
422
- extension = filename.split(/\./).last
423
- filename.sub!(/\..*$/, '')
424
- if filename =~ /_(\d*)$/
425
- newSuffix = $1.to_i + 1
426
- filename = $` + "_#{newSuffix}"
427
- else
428
- filename += "_1"
429
- end
430
- filename += ".#{extension}"
431
- filename
432
- end
433
-
434
- # Breaks a string into lines no longer than <tt>lineLength</tt>.
435
- #
436
- # 'the quick brown fox jumped over the lazy dog.'.line_wrape( 10 ) ->
437
- # "the quick\nbrown fox\njumped\nover the\nlazy dog."
438
- def line_wrape(lineLength)
439
- words = split ' '
440
- line = ''
441
- lines = []
442
- words.each { |word|
443
- if line.length + word.length + 1 > lineLength
444
- lines << line
445
- line = ''
446
- end
447
- line = line != '' ? "#{ line } #{ word }" : word
448
- }
449
- lines << line
450
- lines.join "\n"
451
- end
452
-
453
353
  # Turns a numeric string into U.S. format if it's not already formatted that
454
354
  # way.
455
355
  #
@@ -472,24 +372,6 @@ class String
472
372
  string
473
373
  end
474
374
 
475
- # Divides a string into substrings using <tt>regexp</tt> as a
476
- # delimiter, and returns an array containing both the substrings and the
477
- # portions that matched <tt>regexp</tt>.
478
- #
479
- # 'theZquickZZbrownZfox'.split_keep_in_betweens(/Z+/) ->
480
- # ['the', 'Z', 'quick', 'ZZ', 'brown', 'Z', 'fox' ]
481
- def split_keep_in_betweens(regexp)
482
- result = []
483
- string = clone
484
- while string =~ regexp
485
- result << $`
486
- result << $&
487
- string = $'
488
- end
489
- result << string unless string == ''
490
- result
491
- end
492
-
493
375
  # Returns the camel-case equivalent of an underscore-style string.
494
376
  def underscore_to_camel_case
495
377
  capitalize.gsub( /_([a-zA-Z0-9]+)/ ) { |s| s[1,s.size - 1].capitalize }