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