lafcadio 0.7.3 → 0.7.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/lafcadio.rb +1 -2
- data/lib/lafcadio.rb~ +1 -2
- data/lib/lafcadio/dateTime.rb~ +3 -3
- data/lib/lafcadio/depend.rb +5 -1
- data/lib/lafcadio/depend.rb~ +8 -0
- data/lib/lafcadio/domain.rb +92 -27
- data/lib/lafcadio/domain.rb~ +103 -27
- data/lib/lafcadio/mock.rb +28 -13
- data/lib/lafcadio/mock.rb~ +8 -4
- data/lib/lafcadio/objectField.rb +103 -103
- data/lib/lafcadio/objectField.rb~ +102 -99
- data/lib/lafcadio/objectStore.rb +11 -15
- data/lib/lafcadio/objectStore.rb~ +12 -14
- data/lib/lafcadio/query.rb +42 -16
- data/lib/lafcadio/query.rb~ +44 -23
- data/lib/lafcadio/schema.rb +4 -4
- data/lib/lafcadio/schema.rb~ +56 -0
- data/lib/lafcadio/test.rb +1 -1
- data/lib/lafcadio/test.rb~ +6 -1
- data/lib/lafcadio/util.rb +14 -297
- data/lib/lafcadio/util.rb~ +25 -210
- metadata +48 -6
- data/lib/lafcadio/dateTime.rb +0 -93
data/lib/lafcadio/test.rb
CHANGED
@@ -9,7 +9,7 @@ class LafcadioTestCase < Test::Unit::TestCase
|
|
9
9
|
include Lafcadio
|
10
10
|
|
11
11
|
def setup
|
12
|
-
context = Context.instance
|
12
|
+
context = ContextualService::Context.instance
|
13
13
|
context.flush
|
14
14
|
@mockObjectStore = MockObjectStore.new
|
15
15
|
ObjectStore.set_object_store @mockObjectStore
|
data/lib/lafcadio/test.rb~
CHANGED
@@ -13,7 +13,12 @@ class LafcadioTestCase < Test::Unit::TestCase
|
|
13
13
|
context.flush
|
14
14
|
@mockObjectStore = MockObjectStore.new
|
15
15
|
ObjectStore.set_object_store @mockObjectStore
|
16
|
-
LafcadioConfig.
|
16
|
+
LafcadioConfig.set_values(
|
17
|
+
'classDefinitionDir' => '../test/testData', 'dbhost' => 'localhost',
|
18
|
+
'dbname' => 'test', 'dbpassword' => 'password', 'dbuser' => 'test',
|
19
|
+
'domainFiles' => %w( ../test/mock/domain ),
|
20
|
+
'logdir' => '../test/testOutput/', 'logSql' => 'n'
|
21
|
+
)
|
17
22
|
end
|
18
23
|
|
19
24
|
def default_test; end
|
data/lib/lafcadio/util.rb
CHANGED
@@ -1,220 +1,8 @@
|
|
1
1
|
require 'delegate'
|
2
|
+
require 'lafcadio/depend'
|
2
3
|
require 'singleton'
|
3
4
|
|
4
5
|
module Lafcadio
|
5
|
-
# The Context is a singleton object that manages ContextualServices. Each
|
6
|
-
# ContextualService is a service that connects in some way to external
|
7
|
-
# resources: ObjectStore connects to the database; Emailer connects to SMTP,
|
8
|
-
# etc.
|
9
|
-
#
|
10
|
-
# Context makes it easy to ensure that each ContextualService is only
|
11
|
-
# instantiated once, which can be quite useful for services with expensive
|
12
|
-
# creation.
|
13
|
-
#
|
14
|
-
# Furthermore, Context allows you to explicitly set instances for a given
|
15
|
-
# service, which can be quite useful in testing. For example, once
|
16
|
-
# LafcadioTestCase#setup has an instance of MockObjectStore, it calls
|
17
|
-
# context.setObjectStore @mockObjectStore
|
18
|
-
# which ensures that any future calls to ObjectStore.getObjectStore will
|
19
|
-
# return @mockObjectStore, instead of an instance of ObjectStore connecting
|
20
|
-
# test code to a live database.
|
21
|
-
class Context
|
22
|
-
include Singleton
|
23
|
-
|
24
|
-
def initialize
|
25
|
-
flush
|
26
|
-
@init_procs = {}
|
27
|
-
end
|
28
|
-
|
29
|
-
def create_instance( service_class, *init_args ) #:nodoc:
|
30
|
-
if ( proc = @init_procs[service_class] )
|
31
|
-
proc.call( *init_args )
|
32
|
-
else
|
33
|
-
service_class.new( *init_args )
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# Flushes all cached ContextualServices.
|
38
|
-
def flush
|
39
|
-
@resources_by_class = Hash.new { |hash, key| hash[key] = {} }
|
40
|
-
end
|
41
|
-
|
42
|
-
def get_resource( service_class, *init_args ) #:nodoc:
|
43
|
-
resource = @resources_by_class[service_class][init_args]
|
44
|
-
unless resource
|
45
|
-
resource = create_instance( service_class, *init_args )
|
46
|
-
set_resource( service_class, resource, *init_args )
|
47
|
-
end
|
48
|
-
resource
|
49
|
-
end
|
50
|
-
|
51
|
-
def set_init_proc( service_class, proc )
|
52
|
-
@init_procs[service_class] = proc
|
53
|
-
end
|
54
|
-
|
55
|
-
def set_resource( service_class, resource, *init_args ) #:nodoc:
|
56
|
-
@resources_by_class[service_class][init_args] = resource
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# A ContextualService is a service that is managed by the Context.
|
61
|
-
# ContextualServices are not instantiated normally. Instead, the instance of
|
62
|
-
# such a service may be retrieved by calling the method
|
63
|
-
# < class name >.get< class name >
|
64
|
-
#
|
65
|
-
# For example: ObjectStore.getObjectStore
|
66
|
-
class ContextualService
|
67
|
-
def self.flush; Context.instance.set_resource( self, nil ); end
|
68
|
-
|
69
|
-
def self.method_missing( symbol, *args )
|
70
|
-
method_name = symbol.id2name
|
71
|
-
target = nil
|
72
|
-
if method_name =~ /^get_(.*)/
|
73
|
-
target = :get_resource if $1.underscore_to_camel_case == basename
|
74
|
-
elsif method_name =~ /^set_(.*)/
|
75
|
-
target = :set_resource if $1.underscore_to_camel_case == basename
|
76
|
-
end
|
77
|
-
if target
|
78
|
-
Context.instance.send( target, self, *args )
|
79
|
-
else
|
80
|
-
super
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.set_init_proc
|
85
|
-
proc = proc { yield }
|
86
|
-
Context.instance.set_init_proc( self, proc )
|
87
|
-
end
|
88
|
-
|
89
|
-
# ContextualServices can only be initialized through the Context instance.
|
90
|
-
# Note that if you're writing your own initialize method in a child class,
|
91
|
-
# you should make sure to call super() or you'll overwrite this behavior.
|
92
|
-
def initialize
|
93
|
-
regexp = %r{lafcadio/util\.rb.*create_instance}
|
94
|
-
unless caller.any? { |line| line =~ regexp }
|
95
|
-
raise ArgumentError,
|
96
|
-
"#{ self.class.name.to_s } should be instantiated by calling " +
|
97
|
-
self.class.name.to_s + ".get_" + self.class.name.camel_case_to_underscore,
|
98
|
-
caller
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# A collection of English-language specific utility methods.
|
104
|
-
class English
|
105
|
-
# Turns a camel-case string ("camel_case_to_english") to plain English ("camel
|
106
|
-
# case to english"). Each word is decapitalized.
|
107
|
-
def self.camel_case_to_english(camelCaseStr)
|
108
|
-
words = []
|
109
|
-
nextCapIndex =(camelCaseStr =~ /[A-Z]/)
|
110
|
-
while nextCapIndex != nil
|
111
|
-
words << $` if $`.size > 0
|
112
|
-
camelCaseStr = $& + $'
|
113
|
-
camelCaseStr[0] = camelCaseStr[0..0].downcase
|
114
|
-
nextCapIndex =(camelCaseStr =~ /[A-Z]/)
|
115
|
-
end
|
116
|
-
words << camelCaseStr
|
117
|
-
words.join ' '
|
118
|
-
end
|
119
|
-
|
120
|
-
# Turns an English language string into camel case.
|
121
|
-
def self.english_to_camel_case(englishStr)
|
122
|
-
cc = ""
|
123
|
-
englishStr.split.each { |word|
|
124
|
-
word = word.capitalize unless cc == ''
|
125
|
-
cc = cc += word
|
126
|
-
}
|
127
|
-
cc
|
128
|
-
end
|
129
|
-
|
130
|
-
# Given a singular noun, returns the plural form.
|
131
|
-
def self.plural(singular)
|
132
|
-
consonantYPattern = Regexp.new("([^aeiou])y$", Regexp::IGNORECASE)
|
133
|
-
if singular =~ consonantYPattern
|
134
|
-
singular.gsub consonantYPattern, '\1ies'
|
135
|
-
elsif singular =~ /[xs]$/
|
136
|
-
singular + "es"
|
137
|
-
else
|
138
|
-
singular + "s"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# Returns the proper noun form of a string by capitalizing most of the
|
143
|
-
# words.
|
144
|
-
#
|
145
|
-
# Examples:
|
146
|
-
# English.proper_noun("bosnia and herzegovina") ->
|
147
|
-
# "Bosnia and Herzegovina"
|
148
|
-
# English.proper_noun("macedonia, the former yugoslav republic of") ->
|
149
|
-
# "Macedonia, the Former Yugoslav Republic of"
|
150
|
-
# English.proper_noun("virgin islands, u.s.") ->
|
151
|
-
# "Virgin Islands, U.S."
|
152
|
-
def self.proper_noun(string)
|
153
|
-
proper_noun = ""
|
154
|
-
while(matchIndex = string =~ /[\. ]/)
|
155
|
-
word = string[0..matchIndex-1]
|
156
|
-
word = word.capitalize unless [ 'and', 'the', 'of' ].index(word) != nil
|
157
|
-
proper_noun += word + $&
|
158
|
-
string = string[matchIndex+1..string.length]
|
159
|
-
end
|
160
|
-
word = string
|
161
|
-
word = word.capitalize unless [ 'and', 'the', 'of' ].index(word) != nil
|
162
|
-
proper_noun += word
|
163
|
-
proper_noun
|
164
|
-
end
|
165
|
-
|
166
|
-
# Given a format for a template sentence, generates the sentence while
|
167
|
-
# accounting for details such as pluralization and whether to use "a" or
|
168
|
-
# "an".
|
169
|
-
# [format] The format string. Format codes are:
|
170
|
-
# * %num: Number
|
171
|
-
# * %is: Transitive verb. This will be turned into "is" or "are",
|
172
|
-
# depending on <tt>number</tt>.
|
173
|
-
# * %nam: Name. This will be rendered as either singular or
|
174
|
-
# plural, depending on <tt>number</tt>.
|
175
|
-
# * %a: Indefinite article. This will be turned into "a" or "an",
|
176
|
-
# depending on <tt>name</tt>.
|
177
|
-
# [name] The name of the object being described.
|
178
|
-
# [number] The number of the objects being describes.
|
179
|
-
#
|
180
|
-
# Examples:
|
181
|
-
# English.sentence("There %is currently %num %nam", "product category",
|
182
|
-
# 0) -> "There are currently 0 product categories"
|
183
|
-
# English.sentence("There %is currently %num %nam", "product category",
|
184
|
-
# 1) -> "There is currently 1 product category"
|
185
|
-
# English.sentence("Add %a %nam", "invoice") -> "Add an invoice"
|
186
|
-
def self.sentence(format, name, number = 1)
|
187
|
-
sentence = format
|
188
|
-
sentence.gsub!( /%num/, number.to_s )
|
189
|
-
isVerb = number == 1 ? "is" : "are"
|
190
|
-
sentence.gsub!( /%is/, isVerb )
|
191
|
-
name = English.plural name if number != 1
|
192
|
-
sentence.gsub!( /%nam/, name )
|
193
|
-
article = starts_with_vowel_sound(name) ? 'an' : 'a'
|
194
|
-
sentence.gsub!( /%a/, article )
|
195
|
-
sentence
|
196
|
-
end
|
197
|
-
|
198
|
-
def self.singular(plural)
|
199
|
-
if plural =~ /(.*)ies/
|
200
|
-
$1 + 'y'
|
201
|
-
elsif plural =~ /(.*s)es/
|
202
|
-
$1
|
203
|
-
else
|
204
|
-
plural =~ /(.*)s/
|
205
|
-
$1
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# Does this word start with a vowel sound? "User" and "usury" don't, but
|
210
|
-
# "ugly" does.
|
211
|
-
def self.starts_with_vowel_sound(word)
|
212
|
-
uSomethingUMatch = word =~ /^u[^aeiuo][aeiou]/
|
213
|
-
# 'user' and 'usury' don't start with a vowel sound
|
214
|
-
word =~ /^[aeiou]/ && !uSomethingUMatch
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
6
|
# LafcadioConfig is a Hash that takes its data from the config file. You'll
|
219
7
|
# have to set the location of that file before using it: Use
|
220
8
|
# LafcadioConfig.set_filename.
|
@@ -246,80 +34,16 @@ module Lafcadio
|
|
246
34
|
|
247
35
|
class MissingError < RuntimeError
|
248
36
|
end
|
37
|
+
end
|
249
38
|
|
250
|
-
|
251
|
-
|
252
|
-
# Creates a QueueHash with all the elements in <tt>array</tt> as keys, and
|
253
|
-
# each value initially set to be the same as the corresponding key.
|
254
|
-
def self.new_from_array(array)
|
255
|
-
new( *( ( array.map { |elt| [ elt, elt ] } ).flatten ) )
|
256
|
-
end
|
39
|
+
class String
|
40
|
+
unless method_defined?( :camel_case_to_underscore )
|
257
41
|
|
258
|
-
#
|
259
|
-
|
260
|
-
|
261
|
-
# queueHash[1] => 2
|
262
|
-
# queueHash[3] => 4
|
263
|
-
def initialize(*values)
|
264
|
-
@pairs = []
|
265
|
-
0.step(values.size-1, 2) { |i| @pairs << [ values[i], values[i+1] ] }
|
266
|
-
super( @pairs )
|
42
|
+
# Returns the underscored version of a camel-case string.
|
43
|
+
def camel_case_to_underscore
|
44
|
+
( gsub( /(.)([A-Z])/ ) { $1 + '_' + $2.downcase } ).downcase
|
267
45
|
end
|
268
46
|
|
269
|
-
def ==( otherObj )
|
270
|
-
if otherObj.class == QueueHash && otherObj.size == size
|
271
|
-
( 0..size ).all? { |i|
|
272
|
-
keys[i] == otherObj.keys[i] && values[i] == otherObj.values[i]
|
273
|
-
}
|
274
|
-
else
|
275
|
-
false
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
def [](key)
|
280
|
-
( pair = @pairs.find { |pair| pair[0] == key } ) ? pair.last : nil
|
281
|
-
end
|
282
|
-
|
283
|
-
def []=(key, value); @pairs << [key, value]; end
|
284
|
-
|
285
|
-
def each; @pairs.each { |pair| yield pair[0], pair[1] }; end
|
286
|
-
|
287
|
-
def keys; @pairs.map { |pair| pair[0] }; end
|
288
|
-
|
289
|
-
def values; @pairs.map { |pair| pair[1] }; end
|
290
|
-
end
|
291
|
-
|
292
|
-
class UsStates
|
293
|
-
# Returns a QueueHash of states, with two-letter postal codes as keys and
|
294
|
-
# state names as values.
|
295
|
-
def self.states
|
296
|
-
QueueHash.new( 'AL', 'Alabama', 'AK', 'Alaska', 'AZ', 'Arizona',
|
297
|
-
'AR', 'Arkansas', 'CA', 'California', 'CO', 'Colorado',
|
298
|
-
'CT', 'Connecticut', 'DE', 'Delaware',
|
299
|
-
'DC', 'District of Columbia', 'FL', 'Florida',
|
300
|
-
'GA', 'Georgia', 'HI', 'Hawaii', 'ID', 'Idaho',
|
301
|
-
'IL', 'Illinois', 'IN', 'Indiana', 'IA', 'Iowa',
|
302
|
-
'KS', 'Kansas', 'KY', 'Kentucky', 'LA', 'Louisiana',
|
303
|
-
'ME', 'Maine', 'MD', 'Maryland', 'MA', 'Massachusetts',
|
304
|
-
'MI', 'Michigan', 'MN', 'Minnesota', 'MS', 'Mississippi',
|
305
|
-
'MO', 'Missouri', 'MT', 'Montana', 'NE', 'Nebraska',
|
306
|
-
'NV', 'Nevada', 'NH', 'New Hampshire', 'NJ', 'New Jersey',
|
307
|
-
'NM', 'New Mexico', 'NY', 'New York',
|
308
|
-
'NC', 'North Carolina', 'ND', 'North Dakota', 'OH', 'Ohio',
|
309
|
-
'OK', 'Oklahoma', 'OR', 'Oregon', 'PA', 'Pennsylvania',
|
310
|
-
'PR', 'Puerto Rico', 'RI', 'Rhode Island',
|
311
|
-
'SC', 'South Carolina', 'SD', 'South Dakota',
|
312
|
-
'TN', 'Tennessee', 'TX', 'Texas', 'UT', 'Utah',
|
313
|
-
'VT', 'Vermont', 'VA', 'Virginia', 'WA', 'Washington',
|
314
|
-
'WV', 'West Virginia', 'WI', 'Wisconsin', 'WY', 'Wyoming' )
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
class String
|
320
|
-
# Returns the underscored version of a camel-case string.
|
321
|
-
def camel_case_to_underscore
|
322
|
-
( gsub( /(.)([A-Z])/ ) { $1 + '_' + $2.downcase } ).downcase
|
323
47
|
end
|
324
48
|
|
325
49
|
# Returns the number of times that <tt>regexp</tt> occurs in the string.
|
@@ -352,17 +76,6 @@ class String
|
|
352
76
|
newString
|
353
77
|
end
|
354
78
|
|
355
|
-
# Turns a numeric string into U.S. format if it's not already formatted that
|
356
|
-
# way.
|
357
|
-
#
|
358
|
-
# "10,00".numeric_string_to_us_format -> "10.00"
|
359
|
-
# "10.00".numeric_string_to_us_format -> "10.00"
|
360
|
-
def numeric_string_to_us_format
|
361
|
-
numericString = clone
|
362
|
-
numericString.gsub!(/,/, '.') if numericString =~ /,\d{2}$/
|
363
|
-
numericString
|
364
|
-
end
|
365
|
-
|
366
79
|
# Left-pads a string with +fillChar+ up to +size+ size.
|
367
80
|
#
|
368
81
|
# "a".pad( 10, "+") -> "+++++++++a"
|
@@ -374,8 +87,12 @@ class String
|
|
374
87
|
string
|
375
88
|
end
|
376
89
|
|
377
|
-
|
378
|
-
|
379
|
-
|
90
|
+
unless method_defined?( :underscore_to_camel_case )
|
91
|
+
|
92
|
+
# Returns the camel-case equivalent of an underscore-style string.
|
93
|
+
def underscore_to_camel_case
|
94
|
+
capitalize.gsub( /_([a-zA-Z0-9]+)/ ) { |s| s[1,s.size - 1].capitalize }
|
95
|
+
end
|
96
|
+
|
380
97
|
end
|
381
98
|
end
|
data/lib/lafcadio/util.rb~
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'delegate'
|
2
|
+
require 'lafcadio/depend'
|
2
3
|
require 'singleton'
|
3
4
|
|
4
5
|
module Lafcadio
|
@@ -22,28 +23,28 @@ module Lafcadio
|
|
22
23
|
include Singleton
|
23
24
|
|
24
25
|
def initialize
|
25
|
-
|
26
|
+
flush
|
26
27
|
@init_procs = {}
|
27
28
|
end
|
28
29
|
|
29
|
-
def create_instance( service_class ) #:nodoc:
|
30
|
+
def create_instance( service_class, *init_args ) #:nodoc:
|
30
31
|
if ( proc = @init_procs[service_class] )
|
31
|
-
proc.call
|
32
|
+
proc.call( *init_args )
|
32
33
|
else
|
33
|
-
service_class.new
|
34
|
+
service_class.new( *init_args )
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
38
|
# Flushes all cached ContextualServices.
|
38
39
|
def flush
|
39
|
-
@
|
40
|
+
@resources_by_class = Hash.new { |hash, key| hash[key] = {} }
|
40
41
|
end
|
41
42
|
|
42
|
-
def get_resource( service_class ) #:nodoc:
|
43
|
-
resource = @
|
43
|
+
def get_resource( service_class, *init_args ) #:nodoc:
|
44
|
+
resource = @resources_by_class[service_class][init_args]
|
44
45
|
unless resource
|
45
|
-
resource = create_instance( service_class )
|
46
|
-
set_resource service_class, resource
|
46
|
+
resource = create_instance( service_class, *init_args )
|
47
|
+
set_resource( service_class, resource, *init_args )
|
47
48
|
end
|
48
49
|
resource
|
49
50
|
end
|
@@ -52,8 +53,8 @@ module Lafcadio
|
|
52
53
|
@init_procs[service_class] = proc
|
53
54
|
end
|
54
55
|
|
55
|
-
def set_resource(service_class, resource) #:nodoc:
|
56
|
-
@
|
56
|
+
def set_resource( service_class, resource, *init_args ) #:nodoc:
|
57
|
+
@resources_by_class[service_class][init_args] = resource
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
@@ -100,121 +101,6 @@ module Lafcadio
|
|
100
101
|
end
|
101
102
|
end
|
102
103
|
|
103
|
-
# A collection of English-language specific utility methods.
|
104
|
-
class English
|
105
|
-
# Turns a camel-case string ("camel_case_to_english") to plain English ("camel
|
106
|
-
# case to english"). Each word is decapitalized.
|
107
|
-
def self.camel_case_to_english(camelCaseStr)
|
108
|
-
words = []
|
109
|
-
nextCapIndex =(camelCaseStr =~ /[A-Z]/)
|
110
|
-
while nextCapIndex != nil
|
111
|
-
words << $` if $`.size > 0
|
112
|
-
camelCaseStr = $& + $'
|
113
|
-
camelCaseStr[0] = camelCaseStr[0..0].downcase
|
114
|
-
nextCapIndex =(camelCaseStr =~ /[A-Z]/)
|
115
|
-
end
|
116
|
-
words << camelCaseStr
|
117
|
-
words.join ' '
|
118
|
-
end
|
119
|
-
|
120
|
-
# Turns an English language string into camel case.
|
121
|
-
def self.english_to_camel_case(englishStr)
|
122
|
-
cc = ""
|
123
|
-
englishStr.split.each { |word|
|
124
|
-
word = word.capitalize unless cc == ''
|
125
|
-
cc = cc += word
|
126
|
-
}
|
127
|
-
cc
|
128
|
-
end
|
129
|
-
|
130
|
-
# Given a singular noun, returns the plural form.
|
131
|
-
def self.plural(singular)
|
132
|
-
consonantYPattern = Regexp.new("([^aeiou])y$", Regexp::IGNORECASE)
|
133
|
-
if singular =~ consonantYPattern
|
134
|
-
singular.gsub consonantYPattern, '\1ies'
|
135
|
-
elsif singular =~ /[xs]$/
|
136
|
-
singular + "es"
|
137
|
-
else
|
138
|
-
singular + "s"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# Returns the proper noun form of a string by capitalizing most of the
|
143
|
-
# words.
|
144
|
-
#
|
145
|
-
# Examples:
|
146
|
-
# English.proper_noun("bosnia and herzegovina") ->
|
147
|
-
# "Bosnia and Herzegovina"
|
148
|
-
# English.proper_noun("macedonia, the former yugoslav republic of") ->
|
149
|
-
# "Macedonia, the Former Yugoslav Republic of"
|
150
|
-
# English.proper_noun("virgin islands, u.s.") ->
|
151
|
-
# "Virgin Islands, U.S."
|
152
|
-
def self.proper_noun(string)
|
153
|
-
proper_noun = ""
|
154
|
-
while(matchIndex = string =~ /[\. ]/)
|
155
|
-
word = string[0..matchIndex-1]
|
156
|
-
word = word.capitalize unless [ 'and', 'the', 'of' ].index(word) != nil
|
157
|
-
proper_noun += word + $&
|
158
|
-
string = string[matchIndex+1..string.length]
|
159
|
-
end
|
160
|
-
word = string
|
161
|
-
word = word.capitalize unless [ 'and', 'the', 'of' ].index(word) != nil
|
162
|
-
proper_noun += word
|
163
|
-
proper_noun
|
164
|
-
end
|
165
|
-
|
166
|
-
# Given a format for a template sentence, generates the sentence while
|
167
|
-
# accounting for details such as pluralization and whether to use "a" or
|
168
|
-
# "an".
|
169
|
-
# [format] The format string. Format codes are:
|
170
|
-
# * %num: Number
|
171
|
-
# * %is: Transitive verb. This will be turned into "is" or "are",
|
172
|
-
# depending on <tt>number</tt>.
|
173
|
-
# * %nam: Name. This will be rendered as either singular or
|
174
|
-
# plural, depending on <tt>number</tt>.
|
175
|
-
# * %a: Indefinite article. This will be turned into "a" or "an",
|
176
|
-
# depending on <tt>name</tt>.
|
177
|
-
# [name] The name of the object being described.
|
178
|
-
# [number] The number of the objects being describes.
|
179
|
-
#
|
180
|
-
# Examples:
|
181
|
-
# English.sentence("There %is currently %num %nam", "product category",
|
182
|
-
# 0) -> "There are currently 0 product categories"
|
183
|
-
# English.sentence("There %is currently %num %nam", "product category",
|
184
|
-
# 1) -> "There is currently 1 product category"
|
185
|
-
# English.sentence("Add %a %nam", "invoice") -> "Add an invoice"
|
186
|
-
def self.sentence(format, name, number = 1)
|
187
|
-
sentence = format
|
188
|
-
sentence.gsub!( /%num/, number.to_s )
|
189
|
-
isVerb = number == 1 ? "is" : "are"
|
190
|
-
sentence.gsub!( /%is/, isVerb )
|
191
|
-
name = English.plural name if number != 1
|
192
|
-
sentence.gsub!( /%nam/, name )
|
193
|
-
article = starts_with_vowel_sound(name) ? 'an' : 'a'
|
194
|
-
sentence.gsub!( /%a/, article )
|
195
|
-
sentence
|
196
|
-
end
|
197
|
-
|
198
|
-
def self.singular(plural)
|
199
|
-
if plural =~ /(.*)ies/
|
200
|
-
$1 + 'y'
|
201
|
-
elsif plural =~ /(.*s)es/
|
202
|
-
$1
|
203
|
-
else
|
204
|
-
plural =~ /(.*)s/
|
205
|
-
$1
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# Does this word start with a vowel sound? "User" and "usury" don't, but
|
210
|
-
# "ugly" does.
|
211
|
-
def self.starts_with_vowel_sound(word)
|
212
|
-
uSomethingUMatch = word =~ /^u[^aeiuo][aeiou]/
|
213
|
-
# 'user' and 'usury' don't start with a vowel sound
|
214
|
-
word =~ /^[aeiou]/ && !uSomethingUMatch
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
104
|
# LafcadioConfig is a Hash that takes its data from the config file. You'll
|
219
105
|
# have to set the location of that file before using it: Use
|
220
106
|
# LafcadioConfig.set_filename.
|
@@ -246,80 +132,16 @@ module Lafcadio
|
|
246
132
|
|
247
133
|
class MissingError < RuntimeError
|
248
134
|
end
|
135
|
+
end
|
249
136
|
|
250
|
-
|
251
|
-
|
252
|
-
# Creates a QueueHash with all the elements in <tt>array</tt> as keys, and
|
253
|
-
# each value initially set to be the same as the corresponding key.
|
254
|
-
def self.new_from_array(array)
|
255
|
-
new( *( ( array.map { |elt| [ elt, elt ] } ).flatten ) )
|
256
|
-
end
|
137
|
+
class String
|
138
|
+
unless method_defined?( :camel_case_to_underscore )
|
257
139
|
|
258
|
-
#
|
259
|
-
|
260
|
-
|
261
|
-
# queueHash[1] => 2
|
262
|
-
# queueHash[3] => 4
|
263
|
-
def initialize(*values)
|
264
|
-
@pairs = []
|
265
|
-
0.step(values.size-1, 2) { |i| @pairs << [ values[i], values[i+1] ] }
|
266
|
-
super( @pairs )
|
140
|
+
# Returns the underscored version of a camel-case string.
|
141
|
+
def camel_case_to_underscore
|
142
|
+
( gsub( /(.)([A-Z])/ ) { $1 + '_' + $2.downcase } ).downcase
|
267
143
|
end
|
268
144
|
|
269
|
-
def ==( otherObj )
|
270
|
-
if otherObj.class == QueueHash && otherObj.size == size
|
271
|
-
( 0..size ).all? { |i|
|
272
|
-
keys[i] == otherObj.keys[i] && values[i] == otherObj.values[i]
|
273
|
-
}
|
274
|
-
else
|
275
|
-
false
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
def [](key)
|
280
|
-
( pair = @pairs.find { |pair| pair[0] == key } ) ? pair.last : nil
|
281
|
-
end
|
282
|
-
|
283
|
-
def []=(key, value); @pairs << [key, value]; end
|
284
|
-
|
285
|
-
def each; @pairs.each { |pair| yield pair[0], pair[1] }; end
|
286
|
-
|
287
|
-
def keys; @pairs.map { |pair| pair[0] }; end
|
288
|
-
|
289
|
-
def values; @pairs.map { |pair| pair[1] }; end
|
290
|
-
end
|
291
|
-
|
292
|
-
class UsStates
|
293
|
-
# Returns a QueueHash of states, with two-letter postal codes as keys and
|
294
|
-
# state names as values.
|
295
|
-
def self.states
|
296
|
-
QueueHash.new( 'AL', 'Alabama', 'AK', 'Alaska', 'AZ', 'Arizona',
|
297
|
-
'AR', 'Arkansas', 'CA', 'California', 'CO', 'Colorado',
|
298
|
-
'CT', 'Connecticut', 'DE', 'Delaware',
|
299
|
-
'DC', 'District of Columbia', 'FL', 'Florida',
|
300
|
-
'GA', 'Georgia', 'HI', 'Hawaii', 'ID', 'Idaho',
|
301
|
-
'IL', 'Illinois', 'IN', 'Indiana', 'IA', 'Iowa',
|
302
|
-
'KS', 'Kansas', 'KY', 'Kentucky', 'LA', 'Louisiana',
|
303
|
-
'ME', 'Maine', 'MD', 'Maryland', 'MA', 'Massachusetts',
|
304
|
-
'MI', 'Michigan', 'MN', 'Minnesota', 'MS', 'Mississippi',
|
305
|
-
'MO', 'Missouri', 'MT', 'Montana', 'NE', 'Nebraska',
|
306
|
-
'NV', 'Nevada', 'NH', 'New Hampshire', 'NJ', 'New Jersey',
|
307
|
-
'NM', 'New Mexico', 'NY', 'New York',
|
308
|
-
'NC', 'North Carolina', 'ND', 'North Dakota', 'OH', 'Ohio',
|
309
|
-
'OK', 'Oklahoma', 'OR', 'Oregon', 'PA', 'Pennsylvania',
|
310
|
-
'PR', 'Puerto Rico', 'RI', 'Rhode Island',
|
311
|
-
'SC', 'South Carolina', 'SD', 'South Dakota',
|
312
|
-
'TN', 'Tennessee', 'TX', 'Texas', 'UT', 'Utah',
|
313
|
-
'VT', 'Vermont', 'VA', 'Virginia', 'WA', 'Washington',
|
314
|
-
'WV', 'West Virginia', 'WI', 'Wisconsin', 'WY', 'Wyoming' )
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
class String
|
320
|
-
# Returns the underscored version of a camel-case string.
|
321
|
-
def camel_case_to_underscore
|
322
|
-
( gsub( /(.)([A-Z])/ ) { $1 + '_' + $2.downcase } ).downcase
|
323
145
|
end
|
324
146
|
|
325
147
|
# Returns the number of times that <tt>regexp</tt> occurs in the string.
|
@@ -352,17 +174,6 @@ class String
|
|
352
174
|
newString
|
353
175
|
end
|
354
176
|
|
355
|
-
# Turns a numeric string into U.S. format if it's not already formatted that
|
356
|
-
# way.
|
357
|
-
#
|
358
|
-
# "10,00".numeric_string_to_us_format -> "10.00"
|
359
|
-
# "10.00".numeric_string_to_us_format -> "10.00"
|
360
|
-
def numeric_string_to_us_format
|
361
|
-
numericString = clone
|
362
|
-
numericString.gsub!(/,/, '.') if numericString =~ /,\d{2}$/
|
363
|
-
numericString
|
364
|
-
end
|
365
|
-
|
366
177
|
# Left-pads a string with +fillChar+ up to +size+ size.
|
367
178
|
#
|
368
179
|
# "a".pad( 10, "+") -> "+++++++++a"
|
@@ -374,8 +185,12 @@ class String
|
|
374
185
|
string
|
375
186
|
end
|
376
187
|
|
377
|
-
|
378
|
-
|
379
|
-
|
188
|
+
unless method_defined?( :underscore_to_camel_case )
|
189
|
+
|
190
|
+
# Returns the camel-case equivalent of an underscore-style string.
|
191
|
+
def underscore_to_camel_case
|
192
|
+
capitalize.gsub( /_([a-zA-Z0-9]+)/ ) { |s| s[1,s.size - 1].capitalize }
|
193
|
+
end
|
194
|
+
|
380
195
|
end
|
381
196
|
end
|