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.
- data/bin/lafcadio_schema +12 -4
- data/lib/lafcadio.rb +1 -1
- data/lib/lafcadio.rb~ +1 -1
- data/lib/lafcadio/depend.rb +2 -0
- data/lib/lafcadio/domain.rb +49 -34
- data/lib/lafcadio/domain.rb~ +50 -28
- data/lib/lafcadio/mock.rb +12 -9
- data/lib/lafcadio/objectField.rb +66 -130
- data/lib/lafcadio/objectStore.rb +106 -95
- data/lib/lafcadio/query.rb +87 -78
- data/lib/lafcadio/schema.rb +0 -1
- data/lib/lafcadio/test.rb +4 -1
- data/lib/lafcadio/test/testconfig.dat +0 -2
- data/lib/lafcadio/test/testconfig.dat~ +13 -0
- data/lib/lafcadio/util.rb +2 -120
- data/lib/lafcadio/util.rb~ +379 -0
- metadata +14 -10
- data/lib/lafcadio/TestSuite.rb +0 -18
- data/lib/lafcadio/TestSuite.rb~ +0 -16
- data/lib/lafcadio/dateTime.rb~ +0 -93
- data/lib/lafcadio/mock.rb~ +0 -93
- data/lib/lafcadio/objectField.rb~ +0 -618
- data/lib/lafcadio/objectStore.rb~ +0 -746
- data/lib/lafcadio/query.rb~ +0 -572
- data/lib/lafcadio/test.rb~ +0 -17
data/lib/lafcadio/query.rb
CHANGED
@@ -105,18 +105,18 @@ module Lafcadio
|
|
105
105
|
ASC = 1
|
106
106
|
DESC = 2
|
107
107
|
|
108
|
-
attr_reader :
|
108
|
+
attr_reader :domain_class, :condition
|
109
109
|
attr_accessor :order_by, :order_by_order, :limit
|
110
110
|
|
111
|
-
def initialize(
|
112
|
-
@
|
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(
|
119
|
-
|
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( @
|
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(
|
155
|
-
"#{
|
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 =
|
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 =
|
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 :
|
194
|
+
attr_reader :domain_class
|
195
195
|
|
196
|
-
def initialize(fieldName, searchTerm,
|
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
|
-
@
|
203
|
-
if @
|
204
|
-
unless @
|
205
|
-
raise "Incorrect object type #{ @
|
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
|
-
|
213
|
+
a_domain_class = @domain_class
|
214
214
|
field = nil
|
215
|
-
while (
|
216
|
-
|
217
|
-
|
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
|
-
"#{ @
|
223
|
+
"#{ @domain_class } domain class"
|
226
224
|
raise( MissingError, errStr, caller )
|
227
225
|
end
|
228
226
|
end
|
229
227
|
|
230
|
-
def query; Query.new( @
|
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,
|
264
|
-
super fieldName, searchTerm,
|
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
|
-
@
|
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
|
-
|
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,
|
405
|
-
super fieldName, searchTerm,
|
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(
|
473
|
-
super(
|
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(#{ @
|
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
|
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
|
-
@
|
513
|
+
@field_name = 'pk_id'
|
521
514
|
else
|
522
515
|
@class_field = class_field_or_name
|
523
|
-
@
|
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( @
|
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( @
|
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.
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
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
|
-
|
564
|
-
|
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( @
|
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( @
|
586
|
+
Query::Equals.new( @field_name, true,
|
578
587
|
@domainObjectImpostor.domain_class )
|
579
588
|
else
|
580
589
|
raise
|
data/lib/lafcadio/schema.rb
CHANGED
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 <
|
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 }
|