opal-activesupport 0.3.1 → 0.3.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -0
- data/README.md +4 -1
- data/Rakefile +22 -6
- data/lib/opal/activesupport/version.rb +1 -1
- data/opal-activesupport.gemspec +1 -0
- data/opal/active_support/concern.rb +152 -0
- data/opal/active_support/core_ext/string.rb +1 -38
- data/opal/active_support/core_ext/string/filters.rb +146 -0
- data/opal/active_support/core_ext/string/inflections.rb +66 -4
- data/opal/active_support/inflections.rb +2 -0
- data/opal/active_support/inflector.rb +5 -2
- data/opal/active_support/inflector/inflections.rb +64 -66
- data/opal/active_support/inflector/methods.rb +198 -0
- data/test/abstract_unit.rb +22 -5
- data/test/concern_test.rb +144 -0
- data/test/constantize_test_cases.rb +121 -0
- data/test/core_ext/numeric_ext_test.rb +1 -1
- data/test/core_ext/string_ext_test.rb +675 -304
- data/test/inflector_test.rb +578 -0
- data/test/inflector_test_cases.rb +91 -31
- metadata +27 -4
@@ -1,15 +1,77 @@
|
|
1
1
|
require 'active_support/inflector'
|
2
2
|
|
3
3
|
class String
|
4
|
-
def pluralize
|
5
|
-
|
4
|
+
def pluralize(count = nil, locale = :en)
|
5
|
+
locale = count if count.is_a?(Symbol)
|
6
|
+
if count == 1
|
7
|
+
dup
|
8
|
+
else
|
9
|
+
ActiveSupport::Inflector.pluralize(self, locale)
|
10
|
+
end
|
6
11
|
end
|
7
12
|
|
8
|
-
def singularize
|
9
|
-
ActiveSupport::Inflector.singularize(self)
|
13
|
+
def singularize(locale = :en)
|
14
|
+
ActiveSupport::Inflector.singularize(self, locale)
|
10
15
|
end
|
11
16
|
|
12
17
|
def constantize
|
13
18
|
ActiveSupport::Inflector.constantize(self)
|
14
19
|
end
|
20
|
+
|
21
|
+
def safe_constantize
|
22
|
+
ActiveSupport::Inflector.safe_constantize(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def camelize(first_letter = :upper)
|
26
|
+
case first_letter
|
27
|
+
when :upper
|
28
|
+
ActiveSupport::Inflector.camelize(self, true)
|
29
|
+
when :lower
|
30
|
+
ActiveSupport::Inflector.camelize(self, false)
|
31
|
+
else
|
32
|
+
raise ArgumentError, "Invalid option, use either :upper or :lower."
|
33
|
+
end
|
34
|
+
end
|
35
|
+
alias_method :camelcase, :camelize
|
36
|
+
|
37
|
+
def titleize(keep_id_suffix: false)
|
38
|
+
ActiveSupport::Inflector.titleize(self, keep_id_suffix: keep_id_suffix)
|
39
|
+
end
|
40
|
+
alias_method :titlecase, :titleize
|
41
|
+
|
42
|
+
def underscore
|
43
|
+
ActiveSupport::Inflector.underscore(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
def dasherize
|
47
|
+
ActiveSupport::Inflector.dasherize(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
def demodulize
|
51
|
+
ActiveSupport::Inflector.demodulize(self)
|
52
|
+
end
|
53
|
+
|
54
|
+
def deconstantize
|
55
|
+
ActiveSupport::Inflector.deconstantize(self)
|
56
|
+
end
|
57
|
+
|
58
|
+
def tableize
|
59
|
+
ActiveSupport::Inflector.tableize(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
def classify
|
63
|
+
ActiveSupport::Inflector.classify(self)
|
64
|
+
end
|
65
|
+
|
66
|
+
def humanize(capitalize: true, keep_id_suffix: false)
|
67
|
+
ActiveSupport::Inflector.humanize(self, capitalize: capitalize, keep_id_suffix: keep_id_suffix)
|
68
|
+
end
|
69
|
+
|
70
|
+
def upcase_first
|
71
|
+
ActiveSupport::Inflector.upcase_first(self)
|
72
|
+
end
|
73
|
+
|
74
|
+
def foreign_key(separate_class_name_and_id_with_underscore = true)
|
75
|
+
ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
|
76
|
+
end
|
15
77
|
end
|
@@ -1,2 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "active_support/inflector/inflections"
|
2
|
+
require "active_support/inflector/methods"
|
3
|
+
|
4
|
+
require "active_support/inflections"
|
5
|
+
require "active_support/core_ext/string/inflections"
|
@@ -4,86 +4,67 @@ module ActiveSupport
|
|
4
4
|
module Inflector
|
5
5
|
extend self
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
yield Inflections.instance
|
10
|
-
else
|
11
|
-
Inflections.instance
|
12
|
-
end
|
13
|
-
end
|
7
|
+
class Inflections
|
8
|
+
@__instance__ = {}
|
14
9
|
|
15
|
-
|
16
|
-
|
10
|
+
class Uncountables < Array
|
11
|
+
def <<(*word)
|
12
|
+
add(word)
|
13
|
+
end
|
17
14
|
|
18
|
-
|
19
|
-
|
15
|
+
def add(words)
|
16
|
+
words = words.flatten.map(&:downcase)
|
17
|
+
concat(words)
|
18
|
+
self
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
def uncountable?(str)
|
22
|
+
include?(str.downcase)
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
candidate = constant.const_get(name)
|
29
|
-
next candidate if constant.const_defined?(name, false)
|
30
|
-
next candidate unless Object.const_defined?(name)
|
31
|
-
|
32
|
-
# Go down the ancestors to check if it is owned directly. The check
|
33
|
-
# stops when we reach Object or the end of ancestors tree.
|
34
|
-
constant = constant.ancestors.inject do |const, ancestor|
|
35
|
-
break const if ancestor == Object
|
36
|
-
break ancestor if ancestor.const_defined?(name, false)
|
37
|
-
const
|
38
|
-
end
|
39
|
-
|
40
|
-
# owner is in Object, so raise
|
41
|
-
constant.const_get(name, false)
|
25
|
+
def dup
|
26
|
+
copy = Uncountables.new
|
27
|
+
copy.add(self)
|
28
|
+
copy
|
42
29
|
end
|
43
30
|
end
|
44
|
-
end
|
45
31
|
|
46
|
-
def pluralize(word)
|
47
|
-
apply_inflections(word, inflections.plurals)
|
48
|
-
end
|
49
32
|
|
50
|
-
|
51
|
-
|
52
|
-
|
33
|
+
def self.instance(locale)
|
34
|
+
@__instance__[locale] ||= new
|
35
|
+
end
|
53
36
|
|
54
|
-
|
55
|
-
result = word.to_s
|
37
|
+
attr_reader :plurals, :singulars, :uncountables, :humans
|
56
38
|
|
57
|
-
|
58
|
-
|
59
|
-
else
|
60
|
-
rules.detect do |rule, replacement|
|
61
|
-
break result.sub(rule, replacement) if result.index(rule)
|
62
|
-
end
|
39
|
+
def initialize
|
40
|
+
@plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, []
|
63
41
|
end
|
64
|
-
end
|
65
42
|
|
66
|
-
|
67
|
-
|
68
|
-
|
43
|
+
def initialize_dup(orig) # :nodoc:
|
44
|
+
%w(plurals singulars uncountables humans).each do |scope|
|
45
|
+
instance_variable_set("@#{scope}", orig.send(scope).dup)
|
46
|
+
end
|
69
47
|
end
|
70
48
|
|
71
|
-
attr_reader :plurals, :singulars, :uncountables
|
72
|
-
|
73
|
-
def initialize
|
74
|
-
@plurals, @singulars, @uncountables = [], [], Set.new
|
75
|
-
end
|
76
49
|
|
77
50
|
def plural(rule, replacement)
|
51
|
+
@uncountables.delete(rule) if rule.is_a?(String)
|
52
|
+
@uncountables.delete(replacement)
|
78
53
|
@plurals.unshift([rule, replacement])
|
79
54
|
end
|
80
55
|
|
81
56
|
def singular(rule, replacement)
|
57
|
+
@uncountables.delete(rule) if rule.is_a?(String)
|
58
|
+
@uncountables.delete(replacement)
|
82
59
|
@singulars.unshift([rule, replacement])
|
83
60
|
end
|
84
61
|
|
85
|
-
def uncountable(words)
|
86
|
-
|
62
|
+
def uncountable(*words)
|
63
|
+
@uncountables.add(words)
|
64
|
+
end
|
65
|
+
|
66
|
+
def human(rule, replacement)
|
67
|
+
@humans.unshift([rule, replacement])
|
87
68
|
end
|
88
69
|
|
89
70
|
def irregular(singular, plural)
|
@@ -103,17 +84,34 @@ module ActiveSupport
|
|
103
84
|
singular(/(#{s0})#{srest}$/i, '\1' + srest)
|
104
85
|
singular(/(#{p0})#{prest}$/i, '\1' + srest)
|
105
86
|
else
|
106
|
-
plural(/#{s0.upcase}
|
107
|
-
plural(/#{s0.downcase}
|
108
|
-
plural(/#{p0.upcase}
|
109
|
-
plural(/#{p0.downcase}
|
110
|
-
|
111
|
-
singular(/#{s0.upcase}
|
112
|
-
singular(/#{s0.downcase}
|
113
|
-
singular(/#{p0.upcase}
|
114
|
-
singular(/#{p0.downcase}
|
87
|
+
plural(/#{s0.upcase}#{srest}$/i, p0.upcase + prest)
|
88
|
+
plural(/#{s0.downcase}#{srest}$/i, p0.downcase + prest)
|
89
|
+
plural(/#{p0.upcase}#{prest}$/i, p0.upcase + prest)
|
90
|
+
plural(/#{p0.downcase}#{prest}$/i, p0.downcase + prest)
|
91
|
+
|
92
|
+
singular(/#{s0.upcase}#{srest}$/i, s0.upcase + srest)
|
93
|
+
singular(/#{s0.downcase}#{srest}$/i, s0.downcase + srest)
|
94
|
+
singular(/#{p0.upcase}#{prest}$/i, s0.upcase + srest)
|
95
|
+
singular(/#{p0.downcase}#{prest}$/i, s0.downcase + srest)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def clear(scope = :all)
|
100
|
+
case scope
|
101
|
+
when :all
|
102
|
+
@plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, []
|
103
|
+
else
|
104
|
+
instance_variable_set "@#{scope}", []
|
115
105
|
end
|
116
106
|
end
|
117
107
|
end
|
108
|
+
|
109
|
+
def inflections(locale = :en)
|
110
|
+
if block_given?
|
111
|
+
yield Inflections.instance(locale)
|
112
|
+
else
|
113
|
+
Inflections.instance(locale)
|
114
|
+
end
|
115
|
+
end
|
118
116
|
end
|
119
117
|
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require "active_support/inflections"
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Inflector
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def pluralize(word, locale = :en)
|
8
|
+
apply_inflections(word, inflections(locale).plurals, locale)
|
9
|
+
end
|
10
|
+
|
11
|
+
def singularize(word, locale = :en)
|
12
|
+
apply_inflections(word, inflections(locale).singulars, locale)
|
13
|
+
end
|
14
|
+
|
15
|
+
def camelize(term, uppercase_first_letter = true)
|
16
|
+
string = term.to_s
|
17
|
+
if uppercase_first_letter
|
18
|
+
string = string.sub(/^[a-z\d]*/) { |match| match.capitalize }
|
19
|
+
else
|
20
|
+
string = string.downcase
|
21
|
+
end
|
22
|
+
string = string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
23
|
+
string = string.gsub("/".freeze, "::".freeze)
|
24
|
+
string
|
25
|
+
end
|
26
|
+
|
27
|
+
def underscore(camel_cased_word)
|
28
|
+
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
|
29
|
+
word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze)
|
30
|
+
word = word.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
|
31
|
+
word = word.gsub(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
|
32
|
+
word = word.tr("-".freeze, "_".freeze)
|
33
|
+
word = word.downcase
|
34
|
+
word
|
35
|
+
end
|
36
|
+
|
37
|
+
def humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false)
|
38
|
+
result = lower_case_and_underscored_word.to_s.dup
|
39
|
+
|
40
|
+
inflections.humans.each do |(rule, replacement)|
|
41
|
+
if (rule.is_a?(Regexp) && result =~ rule) || (rule.is_a?(String) && result == rule)
|
42
|
+
result = result.sub(rule, replacement)
|
43
|
+
break
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
result = result.sub(/\A_+/, "".freeze)
|
48
|
+
unless keep_id_suffix
|
49
|
+
result = result.sub(/_id\z/, "".freeze)
|
50
|
+
end
|
51
|
+
result = result.tr("_".freeze, " ".freeze)
|
52
|
+
|
53
|
+
result = result.gsub(/([a-z\d]*)/i) do |match|
|
54
|
+
"#{match.downcase}"
|
55
|
+
end
|
56
|
+
|
57
|
+
if capitalize
|
58
|
+
result = result.sub(/\A\w/) { |match| match.upcase }
|
59
|
+
end
|
60
|
+
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
64
|
+
def upcase_first(string)
|
65
|
+
string.length > 0 ? string[0].upcase + string[1..-1] : ""
|
66
|
+
end
|
67
|
+
|
68
|
+
def titleize(word, keep_id_suffix: false)
|
69
|
+
humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/([a-zA-Z'’`])[a-z]*/) do |match|
|
70
|
+
match.capitalize
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def tableize(class_name)
|
75
|
+
pluralize(underscore(class_name))
|
76
|
+
end
|
77
|
+
|
78
|
+
def classify(table_name)
|
79
|
+
# strip out any leading schema name
|
80
|
+
camelize(singularize(table_name.to_s.sub(/.*\./, "".freeze)))
|
81
|
+
end
|
82
|
+
|
83
|
+
def dasherize(underscored_word)
|
84
|
+
underscored_word.tr("_".freeze, "-".freeze)
|
85
|
+
end
|
86
|
+
|
87
|
+
def demodulize(path)
|
88
|
+
path = path.to_s
|
89
|
+
if i = path.rindex("::")
|
90
|
+
path[(i + 2)..-1]
|
91
|
+
else
|
92
|
+
path
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def deconstantize(path)
|
97
|
+
path.to_s[0, path.rindex("::") || 0] # implementation based on the one in facets' Module#spacename
|
98
|
+
end
|
99
|
+
|
100
|
+
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
|
101
|
+
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
|
102
|
+
end
|
103
|
+
|
104
|
+
def constantize(camel_cased_word)
|
105
|
+
names = camel_cased_word.split('::')
|
106
|
+
|
107
|
+
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
108
|
+
# FIXME: initially was
|
109
|
+
# Object.const_get(camel_cased_word) if names.empty?
|
110
|
+
# Changed because Opal can't handles such case
|
111
|
+
# Instead it throws something like <NoMethodError: undefined method 'upcase' for nil>
|
112
|
+
raise NameError, 'wrong constant name ' if names.empty?
|
113
|
+
|
114
|
+
# Remove the first blank element in case of '::ClassName' notation.
|
115
|
+
names.shift if names.size > 1 && names.first.empty?
|
116
|
+
|
117
|
+
names.inject(Object) do |constant, name|
|
118
|
+
if constant == Object
|
119
|
+
constant.const_get(name)
|
120
|
+
else
|
121
|
+
candidate = constant.const_get(name)
|
122
|
+
next candidate if constant.const_defined?(name, false)
|
123
|
+
next candidate unless Object.const_defined?(name)
|
124
|
+
|
125
|
+
# Go down the ancestors to check if it is owned directly. The check
|
126
|
+
# stops when we reach Object or the end of ancestors tree.
|
127
|
+
constant = constant.ancestors.inject(constant) do |const, ancestor|
|
128
|
+
break const if ancestor == Object
|
129
|
+
break ancestor if ancestor.const_defined?(name, false)
|
130
|
+
const
|
131
|
+
end
|
132
|
+
|
133
|
+
# owner is in Object, so raise
|
134
|
+
constant.const_get(name, false)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def safe_constantize(camel_cased_word)
|
140
|
+
constantize(camel_cased_word)
|
141
|
+
rescue NameError => e
|
142
|
+
raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
|
143
|
+
e.name.to_s == camel_cased_word.to_s)
|
144
|
+
rescue ArgumentError => e
|
145
|
+
raise unless /not missing constant #{const_regexp(camel_cased_word)}!$/.match?(e.message)
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
def ordinal(number)
|
150
|
+
abs_number = number.to_i.abs
|
151
|
+
|
152
|
+
if (11..13).include?(abs_number % 100)
|
153
|
+
"th"
|
154
|
+
else
|
155
|
+
case abs_number % 10
|
156
|
+
when 1; "st"
|
157
|
+
when 2; "nd"
|
158
|
+
when 3; "rd"
|
159
|
+
else "th"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def ordinalize(number)
|
165
|
+
"#{number}#{ordinal(number)}"
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
def const_regexp(camel_cased_word)
|
171
|
+
parts = camel_cased_word.split("::".freeze)
|
172
|
+
|
173
|
+
return Regexp.escape(camel_cased_word) if parts.blank?
|
174
|
+
|
175
|
+
last = parts.pop
|
176
|
+
|
177
|
+
parts.reverse.inject(last) do |acc, part|
|
178
|
+
part.empty? ? acc : "#{part}(::#{acc})?"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def apply_inflections(word, rules, locale = :en)
|
183
|
+
result = word.to_s.dup
|
184
|
+
|
185
|
+
if word.empty? || inflections(locale).uncountables.uncountable?(result)
|
186
|
+
result
|
187
|
+
else
|
188
|
+
rules.each do |(rule, replacement)|
|
189
|
+
if (rule.is_a?(Regexp) && result =~ rule) || (rule.is_a?(String) && result == rule)
|
190
|
+
result = result.sub(rule, replacement)
|
191
|
+
break
|
192
|
+
end
|
193
|
+
end
|
194
|
+
result
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|