swiss_db 0.6.8 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/lib/motion-support/default_inflections.rb +69 -0
- data/lib/motion-support/{inflections.rb → inflector/inflections.rb} +22 -9
- data/lib/motion-support/{methods.rb → inflector/methods.rb} +0 -0
- data/lib/motion-support/string.rb +1 -1
- data/lib/swiss_db/cursor.rb +56 -28
- data/lib/swiss_db/db.rb +6 -7
- data/lib/swiss_db.rb +1 -2
- metadata +5 -5
- data/lib/motion-support/inflector.rb +0 -322
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04bd172ce896a99dd76a23f2670409210a16cbd3
|
4
|
+
data.tar.gz: 234b633535968c2761a3cba2bc056cec691716d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a780767d3fed17e7b36f145a678584e48b7d835c799a9af4732d5cf8ec5ce2d7f17cae428b824b713816209f8746980414791a75e64f736f63125b4db85911a
|
7
|
+
data.tar.gz: cfa8a60bd0dfd045bc8f46823e2373afee309b59734fbe4f26a93ea7c6bf22c30b0930304ff6ca7b7d934d0e90a9f1b7340886acc452404b5f2e37d0d1106836
|
data/README.md
CHANGED
@@ -105,6 +105,9 @@ KNOWN LIMITATION: This ORM compiles in the database name and the database versio
|
|
105
105
|
DataStore.drop_db #=> true if the DB was dropped, false if not
|
106
106
|
```
|
107
107
|
|
108
|
+
## Contributors
|
109
|
+
|
110
|
+
|
108
111
|
## Development
|
109
112
|
|
110
113
|
After checking out the repo, run `bin/setup` to install dependencies.
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#--
|
2
|
+
# Defines the standard inflection rules. These are the starting point for
|
3
|
+
# new projects and are not considered complete. The current set of inflection
|
4
|
+
# rules is frozen. This means, we do not change them to become more complete.
|
5
|
+
# This is a safety measure to keep existing applications from breaking.
|
6
|
+
#++
|
7
|
+
module MotionSupport
|
8
|
+
Inflector.inflections do |inflect|
|
9
|
+
inflect.plural(/$/, 's')
|
10
|
+
inflect.plural(/s$/i, 's')
|
11
|
+
inflect.plural(/^(ax|test)is$/i, '\1es')
|
12
|
+
inflect.plural(/(octop|vir)us$/i, '\1i')
|
13
|
+
inflect.plural(/(octop|vir)i$/i, '\1i')
|
14
|
+
inflect.plural(/(alias|status)$/i, '\1es')
|
15
|
+
inflect.plural(/(bu)s$/i, '\1ses')
|
16
|
+
inflect.plural(/(buffal|tomat)o$/i, '\1oes')
|
17
|
+
inflect.plural(/([ti])um$/i, '\1a')
|
18
|
+
inflect.plural(/([ti])a$/i, '\1a')
|
19
|
+
inflect.plural(/sis$/i, 'ses')
|
20
|
+
inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
|
21
|
+
inflect.plural(/(hive)$/i, '\1s')
|
22
|
+
inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
|
23
|
+
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
|
24
|
+
inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
|
25
|
+
inflect.plural(/^(m|l)ouse$/i, '\1ice')
|
26
|
+
inflect.plural(/^(m|l)ice$/i, '\1ice')
|
27
|
+
inflect.plural(/^(ox)$/i, '\1en')
|
28
|
+
inflect.plural(/^(oxen)$/i, '\1')
|
29
|
+
inflect.plural(/(quiz)$/i, '\1zes')
|
30
|
+
|
31
|
+
inflect.singular(/s$/i, '')
|
32
|
+
inflect.singular(/(ss)$/i, '\1')
|
33
|
+
inflect.singular(/(n)ews$/i, '\1ews')
|
34
|
+
inflect.singular(/([ti])a$/i, '\1um')
|
35
|
+
inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
|
36
|
+
inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
|
37
|
+
inflect.singular(/([^f])ves$/i, '\1fe')
|
38
|
+
inflect.singular(/(hive)s$/i, '\1')
|
39
|
+
inflect.singular(/(tive)s$/i, '\1')
|
40
|
+
inflect.singular(/([lr])ves$/i, '\1f')
|
41
|
+
inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
|
42
|
+
inflect.singular(/(s)eries$/i, '\1eries')
|
43
|
+
inflect.singular(/(m)ovies$/i, '\1ovie')
|
44
|
+
inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
|
45
|
+
inflect.singular(/^(m|l)ice$/i, '\1ouse')
|
46
|
+
inflect.singular(/(bus)(es)?$/i, '\1')
|
47
|
+
inflect.singular(/(o)es$/i, '\1')
|
48
|
+
inflect.singular(/(shoe)s$/i, '\1')
|
49
|
+
inflect.singular(/(cris|test)(is|es)$/i, '\1is')
|
50
|
+
inflect.singular(/^(a)x[ie]s$/i, '\1xis')
|
51
|
+
inflect.singular(/(octop|vir)(us|i)$/i, '\1us')
|
52
|
+
inflect.singular(/(alias|status)(es)?$/i, '\1')
|
53
|
+
inflect.singular(/^(ox)en/i, '\1')
|
54
|
+
inflect.singular(/(vert|ind)ices$/i, '\1ex')
|
55
|
+
inflect.singular(/(matr)ices$/i, '\1ix')
|
56
|
+
inflect.singular(/(quiz)zes$/i, '\1')
|
57
|
+
inflect.singular(/(database)s$/i, '\1')
|
58
|
+
|
59
|
+
inflect.irregular('person', 'people')
|
60
|
+
inflect.irregular('man', 'men')
|
61
|
+
inflect.irregular('child', 'children')
|
62
|
+
inflect.irregular('sex', 'sexes')
|
63
|
+
inflect.irregular('move', 'moves')
|
64
|
+
inflect.irregular('zombie', 'zombies')
|
65
|
+
|
66
|
+
inflect.uncountable(%w(equipment information rice money species series fish sheep jeans police))
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -158,18 +158,31 @@ module MotionSupport
|
|
158
158
|
singular(/(#{s0})#{srest}$/i, '\1' + srest)
|
159
159
|
singular(/(#{p0})#{prest}$/i, '\1' + srest)
|
160
160
|
else
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
singular(/#{p0.downcase}(?i)#{prest}$/, s0.downcase + srest)
|
161
|
+
# define_plurals and define_singulars arose from a strange error where
|
162
|
+
# the app would quit with absolutely no output (not even VM Aborting!).
|
163
|
+
# The only way to turn off the error was to comment out some lines, but
|
164
|
+
# it didn't really matter which ones, as long as you commented out 4 or 5.
|
165
|
+
# So I split them out like this on a whim and it seems to have solved the problem.
|
166
|
+
# Weird!!
|
167
|
+
define_plurals(s0, srest, p0, prest)
|
168
|
+
define_singulars(s0, srest, p0, prest)
|
170
169
|
end
|
171
170
|
end
|
172
171
|
|
172
|
+
def define_plurals(s0, srest, p0, prest)
|
173
|
+
plural(/#{s0.upcase}(?i)#{srest}$/, p0.upcase + prest)
|
174
|
+
plural(/#{s0.downcase}(?i)#{srest}$/, p0.downcase + prest)
|
175
|
+
plural(/#{p0.upcase}(?i)#{prest}$/, p0.upcase + prest)
|
176
|
+
plural(/#{p0.downcase}(?i)#{prest}$/, p0.downcase + prest)
|
177
|
+
end
|
178
|
+
|
179
|
+
def define_singulars(s0, srest, p0, prest)
|
180
|
+
singular(/#{s0.upcase}(?i)#{srest}$/, s0.upcase + srest)
|
181
|
+
singular(/#{s0.downcase}(?i)#{srest}$/, s0.downcase + srest)
|
182
|
+
singular(/#{p0.upcase}(?i)#{prest}$/, s0.upcase + srest)
|
183
|
+
singular(/#{p0.downcase}(?i)#{prest}$/, s0.downcase + srest)
|
184
|
+
end
|
185
|
+
|
173
186
|
# Add uncountable words that shouldn't be attempted inflected.
|
174
187
|
#
|
175
188
|
# uncountable 'money'
|
File without changes
|
data/lib/swiss_db/cursor.rb
CHANGED
@@ -20,11 +20,11 @@ end
|
|
20
20
|
|
21
21
|
class Cursor # < Array
|
22
22
|
|
23
|
-
FIELD_TYPE_BLOB
|
24
|
-
FIELD_TYPE_FLOAT
|
23
|
+
FIELD_TYPE_BLOB = 4
|
24
|
+
FIELD_TYPE_FLOAT = 2
|
25
25
|
FIELD_TYPE_INTEGER = 1
|
26
|
-
FIELD_TYPE_NULL
|
27
|
-
FIELD_TYPE_STRING
|
26
|
+
FIELD_TYPE_NULL = 0
|
27
|
+
FIELD_TYPE_STRING = 3
|
28
28
|
|
29
29
|
attr_accessor :cursor, :model
|
30
30
|
|
@@ -52,7 +52,7 @@ class Cursor # < Array
|
|
52
52
|
# puts i
|
53
53
|
hash_obj = {}
|
54
54
|
cursor.moveToPosition(i)
|
55
|
-
$current_schema[model.
|
55
|
+
$current_schema[model.table_name].each do |k, v|
|
56
56
|
hash_obj[k.to_sym] = self.send(k.to_sym)
|
57
57
|
end
|
58
58
|
arr << CursorModel.new(hash_obj)
|
@@ -60,33 +60,55 @@ class Cursor # < Array
|
|
60
60
|
arr
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
64
|
-
|
63
|
+
def method_missing(methId, *args)
|
64
|
+
method_name = methId.id2name
|
65
|
+
|
66
|
+
if valid_setter_getter?(method_name)
|
67
|
+
handle_get_or_set(method_name, args)
|
68
|
+
else
|
69
|
+
super
|
70
|
+
end
|
65
71
|
end
|
66
72
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
73
|
+
def valid_setter_getter?(method_name)
|
74
|
+
method_name.chop! if is_setter? method_name
|
75
|
+
column_names.include? method_name
|
76
|
+
end
|
77
|
+
|
78
|
+
def handle_get_or_set(method_name, args)
|
79
|
+
if is_setter? method_name
|
80
|
+
set_method(args)
|
81
|
+
else
|
82
|
+
get_method(method_name)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def is_setter?(method_name)
|
87
|
+
method_name[-1] == '='
|
88
|
+
end
|
89
|
+
|
90
|
+
def get_method(method_name)
|
91
|
+
index = cursor.getColumnIndex(method_name)
|
92
|
+
type = cursor.getType(index)
|
93
|
+
# puts "getting field #{method_name} at index #{index} of type #{type}"
|
94
|
+
|
95
|
+
if type == FIELD_TYPE_STRING
|
96
|
+
cursor.getString(index)
|
97
|
+
elsif type == FIELD_TYPE_INTEGER
|
98
|
+
cursor.getInt(index)
|
99
|
+
elsif type == FIELD_TYPE_NULL
|
100
|
+
nil #??
|
101
|
+
elsif type == FIELD_TYPE_FLOAT
|
102
|
+
cursor.getFloat(index)
|
103
|
+
elsif type == FIELD_TYPE_BLOB
|
104
|
+
cursor.getBlob(index)
|
87
105
|
end
|
88
106
|
end
|
89
107
|
|
108
|
+
def set_method(method_name, args)
|
109
|
+
@values[method_name.chop] = args[0]
|
110
|
+
end
|
111
|
+
|
90
112
|
def save
|
91
113
|
primary_key = model.primary_key
|
92
114
|
pk_value = self.send(primary_key.to_sym)
|
@@ -100,5 +122,11 @@ class Cursor # < Array
|
|
100
122
|
model.store.update(model.table_name, {key => value}, {primary_key => pk_value})
|
101
123
|
end
|
102
124
|
|
125
|
+
def count
|
126
|
+
cursor.getCount
|
127
|
+
end
|
103
128
|
|
104
|
-
|
129
|
+
def column_names
|
130
|
+
cursor.getColumnNames
|
131
|
+
end
|
132
|
+
end
|
data/lib/swiss_db/db.rb
CHANGED
@@ -30,7 +30,8 @@ class Object
|
|
30
30
|
puts @current_schema.inspect
|
31
31
|
end
|
32
32
|
|
33
|
-
def entity(
|
33
|
+
def entity(class_name, &block)
|
34
|
+
table_name = class_name.tableize
|
34
35
|
puts "adding entity #{table_name} to schema"
|
35
36
|
@table_name = table_name
|
36
37
|
@current_schema[@table_name] = {}
|
@@ -43,8 +44,10 @@ class Object
|
|
43
44
|
@current_schema[@table_name][name] = type
|
44
45
|
end
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
%w(boolean float double integer datetime).each do |type|
|
48
|
+
define_method(type) do |column_name|
|
49
|
+
add_column column_name.to_s, type.upcase
|
50
|
+
end
|
48
51
|
end
|
49
52
|
|
50
53
|
def string(column_name)
|
@@ -55,8 +58,4 @@ class Object
|
|
55
58
|
add_column column_name.to_s, "INTEGER"
|
56
59
|
end
|
57
60
|
|
58
|
-
def double(column_name)
|
59
|
-
add_column column_name.to_s, "DOUBLE"
|
60
|
-
end
|
61
|
-
|
62
61
|
end
|
data/lib/swiss_db.rb
CHANGED
@@ -14,7 +14,7 @@ if defined?(Motion) && defined?(Motion::Project::Config)
|
|
14
14
|
insert_point = app.files.find_index { |file| file =~ /^(?:\.\/)?app\// } || 0
|
15
15
|
|
16
16
|
# change to "swiss_db" for just swiss_db
|
17
|
-
Dir.glob(File.join(lib_dir_path, "**/*.rb")).
|
17
|
+
Dir.glob(File.join(lib_dir_path, "**/*.rb")).each do |file|
|
18
18
|
app.files.insert(insert_point, file)
|
19
19
|
end
|
20
20
|
|
@@ -25,4 +25,3 @@ if defined?(Motion) && defined?(Motion::Project::Config)
|
|
25
25
|
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swiss_db
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Silverman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -47,9 +47,9 @@ extra_rdoc_files: []
|
|
47
47
|
files:
|
48
48
|
- README.md
|
49
49
|
- lib/motion-support/array.rb
|
50
|
-
- lib/motion-support/
|
51
|
-
- lib/motion-support/inflector.rb
|
52
|
-
- lib/motion-support/methods.rb
|
50
|
+
- lib/motion-support/default_inflections.rb
|
51
|
+
- lib/motion-support/inflector/inflections.rb
|
52
|
+
- lib/motion-support/inflector/methods.rb
|
53
53
|
- lib/motion-support/string.rb
|
54
54
|
- lib/swiss_db.rb
|
55
55
|
- lib/swiss_db/cursor.rb
|
@@ -1,322 +0,0 @@
|
|
1
|
-
module MotionSupport
|
2
|
-
# The Inflector transforms words from singular to plural, class names to table
|
3
|
-
# names, modularized class names to ones without, and class names to foreign
|
4
|
-
# keys. The default inflections for pluralization, singularization, and
|
5
|
-
# uncountable words are kept in inflections.rb.
|
6
|
-
module Inflector
|
7
|
-
class << self
|
8
|
-
|
9
|
-
# Returns the plural form of the word in the string.
|
10
|
-
#
|
11
|
-
# 'post'.pluralize # => "posts"
|
12
|
-
# 'octopus'.pluralize # => "octopi"
|
13
|
-
# 'sheep'.pluralize # => "sheep"
|
14
|
-
# 'words'.pluralize # => "words"
|
15
|
-
# 'CamelOctopus'.pluralize # => "CamelOctopi"
|
16
|
-
def pluralize(word)
|
17
|
-
apply_inflections(word, inflections.plurals)
|
18
|
-
end
|
19
|
-
|
20
|
-
# The reverse of +pluralize+, returns the singular form of a word in a
|
21
|
-
# string.
|
22
|
-
#
|
23
|
-
# 'posts'.singularize # => "post"
|
24
|
-
# 'octopi'.singularize # => "octopus"
|
25
|
-
# 'sheep'.singularize # => "sheep"
|
26
|
-
# 'word'.singularize # => "word"
|
27
|
-
# 'CamelOctopi'.singularize # => "CamelOctopus"
|
28
|
-
def singularize(word)
|
29
|
-
apply_inflections(word, inflections.singulars)
|
30
|
-
end
|
31
|
-
|
32
|
-
# By default, +camelize+ converts strings to UpperCamelCase. If the argument
|
33
|
-
# to +camelize+ is set to <tt>:lower</tt> then +camelize+ produces
|
34
|
-
# lowerCamelCase.
|
35
|
-
#
|
36
|
-
# +camelize+ will also convert '/' to '::' which is useful for converting
|
37
|
-
# paths to namespaces.
|
38
|
-
#
|
39
|
-
# 'active_model'.camelize # => "ActiveModel"
|
40
|
-
# 'active_model'.camelize(:lower) # => "activeModel"
|
41
|
-
# 'active_model/errors'.camelize # => "ActiveModel::Errors"
|
42
|
-
# 'active_model/errors'.camelize(:lower) # => "activeModel::Errors"
|
43
|
-
#
|
44
|
-
# As a rule of thumb you can think of +camelize+ as the inverse of
|
45
|
-
# +underscore+, though there are cases where that does not hold:
|
46
|
-
#
|
47
|
-
# 'SSLError'.underscore.camelize # => "SslError"
|
48
|
-
def camelize(term, uppercase_first_letter = true)
|
49
|
-
string = term.to_s
|
50
|
-
if uppercase_first_letter
|
51
|
-
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize }
|
52
|
-
else
|
53
|
-
string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
|
54
|
-
end
|
55
|
-
string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }.gsub('/', '::')
|
56
|
-
end
|
57
|
-
|
58
|
-
# Makes an underscored, lowercase form from the expression in the string.
|
59
|
-
#
|
60
|
-
# Changes '::' to '/' to convert namespaces to paths.
|
61
|
-
#
|
62
|
-
# 'ActiveModel'.underscore # => "active_model"
|
63
|
-
# 'ActiveModel::Errors'.underscore # => "active_model/errors"
|
64
|
-
#
|
65
|
-
# As a rule of thumb you can think of +underscore+ as the inverse of
|
66
|
-
# +camelize+, though there are cases where that does not hold:
|
67
|
-
#
|
68
|
-
# 'SSLError'.underscore.camelize # => "SslError"
|
69
|
-
def underscore(camel_cased_word)
|
70
|
-
word = camel_cased_word.to_s.dup
|
71
|
-
word.gsub!('::', '/')
|
72
|
-
word.gsub!(/(?:([A-Za-z\d])|^)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
|
73
|
-
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
74
|
-
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
75
|
-
word.gsub!("-", "_")
|
76
|
-
word.downcase!
|
77
|
-
word
|
78
|
-
end
|
79
|
-
|
80
|
-
# Capitalizes the first word and turns underscores into spaces and strips a
|
81
|
-
# trailing "_id", if any. Like +titleize+, this is meant for creating pretty
|
82
|
-
# output.
|
83
|
-
#
|
84
|
-
# 'employee_salary'.humanize # => "Employee salary"
|
85
|
-
# 'author_id'.humanize # => "Author"
|
86
|
-
def humanize(lower_case_and_underscored_word)
|
87
|
-
result = lower_case_and_underscored_word.to_s.dup
|
88
|
-
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
89
|
-
result.gsub!(/_id$/, "")
|
90
|
-
result.gsub!('_', ' ')
|
91
|
-
result.gsub(/([a-z\d]*)/i) { |match|
|
92
|
-
"#{inflections.acronyms[match] || match.downcase}"
|
93
|
-
}.gsub(/^\w/) { |match| match.upcase }
|
94
|
-
end
|
95
|
-
|
96
|
-
# Capitalizes all the words and replaces some characters in the string to
|
97
|
-
# create a nicer looking title. +titleize+ is meant for creating pretty
|
98
|
-
# output. It is not used in the Rails internals.
|
99
|
-
#
|
100
|
-
# +titleize+ is also aliased as +titlecase+.
|
101
|
-
#
|
102
|
-
# 'man from the boondocks'.titleize # => "Man From The Boondocks"
|
103
|
-
# 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
|
104
|
-
# 'TheManWithoutAPast'.titleize # => "The Man Without A Past"
|
105
|
-
# 'raiders_of_the_lost_ark'.titleize # => "Raiders Of The Lost Ark"
|
106
|
-
def titleize(word)
|
107
|
-
humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { |match| match.capitalize }
|
108
|
-
end
|
109
|
-
|
110
|
-
# Create the name of a table like Rails does for models to table names. This
|
111
|
-
# method uses the +pluralize+ method on the last word in the string.
|
112
|
-
#
|
113
|
-
# 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
|
114
|
-
# 'egg_and_ham'.tableize # => "egg_and_hams"
|
115
|
-
# 'fancyCategory'.tableize # => "fancy_categories"
|
116
|
-
def tableize(class_name)
|
117
|
-
pluralize(underscore(class_name))
|
118
|
-
end
|
119
|
-
|
120
|
-
# Create a class name from a plural table name like Rails does for table
|
121
|
-
# names to models. Note that this returns a string and not a Class (To
|
122
|
-
# convert to an actual class follow +classify+ with +constantize+).
|
123
|
-
#
|
124
|
-
# 'egg_and_hams'.classify # => "EggAndHam"
|
125
|
-
# 'posts'.classify # => "Post"
|
126
|
-
#
|
127
|
-
# Singular names are not handled correctly:
|
128
|
-
#
|
129
|
-
# 'business'.classify # => "Busines"
|
130
|
-
def classify(table_name)
|
131
|
-
# strip out any leading schema name
|
132
|
-
camelize(singularize(table_name.to_s.sub(/.*\./, '')))
|
133
|
-
end
|
134
|
-
|
135
|
-
# Replaces underscores with dashes in the string.
|
136
|
-
#
|
137
|
-
# 'puni_puni'.dasherize # => "puni-puni"
|
138
|
-
def dasherize(underscored_word)
|
139
|
-
underscored_word.gsub('_', '-')
|
140
|
-
end
|
141
|
-
|
142
|
-
# Removes the module part from the expression in the string.
|
143
|
-
#
|
144
|
-
# 'ActiveRecord::CoreExtensions::String::Inflections'.demodulize # => "Inflections"
|
145
|
-
# 'Inflections'.demodulize # => "Inflections"
|
146
|
-
#
|
147
|
-
# See also +deconstantize+.
|
148
|
-
def demodulize(path)
|
149
|
-
path = path.to_s
|
150
|
-
if i = path.rindex('::')
|
151
|
-
path[(i+2)..-1]
|
152
|
-
else
|
153
|
-
path
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
# Removes the rightmost segment from the constant expression in the string.
|
158
|
-
#
|
159
|
-
# 'Net::HTTP'.deconstantize # => "Net"
|
160
|
-
# '::Net::HTTP'.deconstantize # => "::Net"
|
161
|
-
# 'String'.deconstantize # => ""
|
162
|
-
# '::String'.deconstantize # => ""
|
163
|
-
# ''.deconstantize # => ""
|
164
|
-
#
|
165
|
-
# See also +demodulize+.
|
166
|
-
def deconstantize(path)
|
167
|
-
path.to_s[0...(path.rindex('::') || 0)] # implementation based on the one in facets' Module#spacename
|
168
|
-
end
|
169
|
-
|
170
|
-
# Creates a foreign key name from a class name.
|
171
|
-
# +separate_class_name_and_id_with_underscore+ sets whether
|
172
|
-
# the method should put '_' between the name and 'id'.
|
173
|
-
#
|
174
|
-
# 'Message'.foreign_key # => "message_id"
|
175
|
-
# 'Message'.foreign_key(false) # => "messageid"
|
176
|
-
# 'Admin::Post'.foreign_key # => "post_id"
|
177
|
-
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
|
178
|
-
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
|
179
|
-
end
|
180
|
-
|
181
|
-
# Tries to find a constant with the name specified in the argument string.
|
182
|
-
#
|
183
|
-
# 'Module'.constantize # => Module
|
184
|
-
# 'Test::Unit'.constantize # => Test::Unit
|
185
|
-
#
|
186
|
-
# The name is assumed to be the one of a top-level constant, no matter
|
187
|
-
# whether it starts with "::" or not. No lexical context is taken into
|
188
|
-
# account:
|
189
|
-
#
|
190
|
-
# C = 'outside'
|
191
|
-
# module M
|
192
|
-
# C = 'inside'
|
193
|
-
# C # => 'inside'
|
194
|
-
# 'C'.constantize # => 'outside', same as ::C
|
195
|
-
# end
|
196
|
-
#
|
197
|
-
# NameError is raised when the name is not in CamelCase or the constant is
|
198
|
-
# unknown.
|
199
|
-
def constantize(camel_cased_word)
|
200
|
-
names = camel_cased_word.split('::')
|
201
|
-
names.shift if names.empty? || names.first.empty?
|
202
|
-
|
203
|
-
names.inject(Object) do |constant, name|
|
204
|
-
if constant == Object
|
205
|
-
constant.const_get(name)
|
206
|
-
else
|
207
|
-
candidate = constant.const_get(name)
|
208
|
-
next candidate if constant.const_defined?(name, false)
|
209
|
-
next candidate unless Object.const_defined?(name)
|
210
|
-
|
211
|
-
# Go down the ancestors to check it it's owned
|
212
|
-
# directly before we reach Object or the end of ancestors.
|
213
|
-
constant = constant.ancestors.inject do |const, ancestor|
|
214
|
-
break const if ancestor == Object
|
215
|
-
break ancestor if ancestor.const_defined?(name, false)
|
216
|
-
const
|
217
|
-
end
|
218
|
-
|
219
|
-
# owner is in Object, so raise
|
220
|
-
constant.const_get(name, false)
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
# Tries to find a constant with the name specified in the argument string.
|
226
|
-
#
|
227
|
-
# 'Module'.safe_constantize # => Module
|
228
|
-
# 'Test::Unit'.safe_constantize # => Test::Unit
|
229
|
-
#
|
230
|
-
# The name is assumed to be the one of a top-level constant, no matter
|
231
|
-
# whether it starts with "::" or not. No lexical context is taken into
|
232
|
-
# account:
|
233
|
-
#
|
234
|
-
# C = 'outside'
|
235
|
-
# module M
|
236
|
-
# C = 'inside'
|
237
|
-
# C # => 'inside'
|
238
|
-
# 'C'.safe_constantize # => 'outside', same as ::C
|
239
|
-
# end
|
240
|
-
#
|
241
|
-
# +nil+ is returned when the name is not in CamelCase or the constant (or
|
242
|
-
# part of it) is unknown.
|
243
|
-
#
|
244
|
-
# 'blargle'.safe_constantize # => nil
|
245
|
-
# 'UnknownModule'.safe_constantize # => nil
|
246
|
-
# 'UnknownModule::Foo::Bar'.safe_constantize # => nil
|
247
|
-
def safe_constantize(camel_cased_word)
|
248
|
-
constantize(camel_cased_word)
|
249
|
-
rescue NameError => e
|
250
|
-
raise unless e.message =~ /(uninitialized constant|wrong constant name) #{const_regexp(camel_cased_word)}$/ ||
|
251
|
-
e.name.to_s == camel_cased_word.to_s
|
252
|
-
rescue ArgumentError => e
|
253
|
-
raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
|
254
|
-
end
|
255
|
-
|
256
|
-
# Returns the suffix that should be added to a number to denote the position
|
257
|
-
# in an ordered sequence such as 1st, 2nd, 3rd, 4th.
|
258
|
-
#
|
259
|
-
# ordinal(1) # => "st"
|
260
|
-
# ordinal(2) # => "nd"
|
261
|
-
# ordinal(1002) # => "nd"
|
262
|
-
# ordinal(1003) # => "rd"
|
263
|
-
# ordinal(-11) # => "th"
|
264
|
-
# ordinal(-1021) # => "st"
|
265
|
-
def ordinal(number)
|
266
|
-
abs_number = number.to_i.abs
|
267
|
-
|
268
|
-
if (11..13).include?(abs_number % 100)
|
269
|
-
"th"
|
270
|
-
else
|
271
|
-
case abs_number % 10
|
272
|
-
when 1; "st"
|
273
|
-
when 2; "nd"
|
274
|
-
when 3; "rd"
|
275
|
-
else "th"
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
# Turns a number into an ordinal string used to denote the position in an
|
281
|
-
# ordered sequence such as 1st, 2nd, 3rd, 4th.
|
282
|
-
#
|
283
|
-
# ordinalize(1) # => "1st"
|
284
|
-
# ordinalize(2) # => "2nd"
|
285
|
-
# ordinalize(1002) # => "1002nd"
|
286
|
-
# ordinalize(1003) # => "1003rd"
|
287
|
-
# ordinalize(-11) # => "-11th"
|
288
|
-
# ordinalize(-1021) # => "-1021st"
|
289
|
-
def ordinalize(number)
|
290
|
-
"#{number}#{ordinal(number)}"
|
291
|
-
end
|
292
|
-
|
293
|
-
private
|
294
|
-
|
295
|
-
# Mount a regular expression that will match part by part of the constant.
|
296
|
-
# For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)?
|
297
|
-
def const_regexp(camel_cased_word) #:nodoc:
|
298
|
-
parts = camel_cased_word.split("::")
|
299
|
-
last = parts.pop
|
300
|
-
|
301
|
-
parts.reverse.inject(last) do |acc, part|
|
302
|
-
part.empty? ? acc : "#{part}(::#{acc})?"
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
# Applies inflection rules for +singularize+ and +pluralize+.
|
307
|
-
#
|
308
|
-
# apply_inflections('post', inflections.plurals) # => "posts"
|
309
|
-
# apply_inflections('posts', inflections.singulars) # => "post"
|
310
|
-
def apply_inflections(word, rules)
|
311
|
-
result = word.to_s.dup
|
312
|
-
|
313
|
-
if word.empty? || inflections.uncountables.include?(result.downcase[/\b\w+\Z/])
|
314
|
-
result
|
315
|
-
else
|
316
|
-
rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
317
|
-
result
|
318
|
-
end
|
319
|
-
end
|
320
|
-
end
|
321
|
-
end
|
322
|
-
end
|