lafcadio 0.5.2 → 0.6.0

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