lafcadio 0.7.3 → 0.7.4
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/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
|