gorillib 0.1.11 → 0.4.0pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rspec +1 -2
- data/.yardopts +9 -0
- data/{CHANGELOG.textile → CHANGELOG.md} +35 -9
- data/Gemfile +21 -14
- data/Guardfile +19 -0
- data/{LICENSE.textile → LICENSE.md} +43 -29
- data/README.md +47 -52
- data/Rakefile +31 -30
- data/TODO.md +32 -0
- data/VERSION +1 -1
- data/examples/builder/ironfan.rb +133 -0
- data/examples/model/simple.rb +17 -0
- data/gorillib.gemspec +106 -86
- data/lib/alt/kernel/call_stack.rb +56 -0
- data/lib/gorillib/array/wrap.rb +53 -0
- data/lib/gorillib/base.rb +3 -3
- data/lib/gorillib/builder/field.rb +5 -0
- data/lib/gorillib/builder.rb +260 -0
- data/lib/gorillib/collection/has_collection.rb +31 -0
- data/lib/gorillib/collection.rb +129 -0
- data/lib/gorillib/configurable.rb +28 -0
- data/lib/gorillib/datetime/{flat.rb → to_flat.rb} +0 -0
- data/lib/gorillib/exception/confidence.rb +17 -0
- data/lib/gorillib/exception/raisers.rb +78 -0
- data/lib/gorillib/hash/mash.rb +202 -0
- data/lib/gorillib/hashlike/slice.rb +53 -19
- data/lib/gorillib/hashlike.rb +5 -3
- data/lib/gorillib/io/system_helpers.rb +30 -0
- data/lib/gorillib/logger/log.rb +18 -0
- data/lib/gorillib/metaprogramming/concern.rb +124 -0
- data/lib/gorillib/model/active_model_conversion.rb +68 -0
- data/lib/gorillib/model/active_model_naming.rb +87 -0
- data/lib/gorillib/model/active_model_shim.rb +33 -0
- data/lib/gorillib/model/base.rb +341 -0
- data/lib/gorillib/model/defaults.rb +71 -0
- data/lib/gorillib/model/errors.rb +14 -0
- data/lib/gorillib/model/factories.rb +372 -0
- data/lib/gorillib/model/field.rb +146 -0
- data/lib/gorillib/model/named_schema.rb +53 -0
- data/lib/gorillib/{struct/hashlike_iteration.rb → model/overlay.rb} +0 -0
- data/lib/gorillib/model/record_schema.rb +9 -0
- data/lib/gorillib/model/serialization.rb +23 -0
- data/lib/gorillib/model/validate.rb +22 -0
- data/lib/gorillib/model.rb +23 -0
- data/lib/gorillib/pathname.rb +78 -0
- data/lib/gorillib/{serialization.rb → serialization/to_wire.rb} +0 -0
- data/lib/gorillib/some.rb +11 -9
- data/lib/gorillib/string/constantize.rb +21 -14
- data/lib/gorillib/string/inflections.rb +6 -76
- data/lib/gorillib/string/inflector.rb +192 -0
- data/lib/gorillib/string/simple_inflector.rb +267 -0
- data/lib/gorillib/type/extended.rb +52 -0
- data/lib/gorillib/utils/capture_output.rb +28 -0
- data/lib/gorillib/utils/console.rb +131 -0
- data/lib/gorillib/utils/nuke_constants.rb +9 -0
- data/lib/gorillib/utils/stub_module.rb +33 -0
- data/spec/examples/builder/ironfan_spec.rb +37 -0
- data/spec/extlib/hash_spec.rb +64 -0
- data/spec/extlib/mash_spec.rb +312 -0
- data/spec/{array → gorillib/array}/compact_blank_spec.rb +2 -2
- data/spec/{array → gorillib/array}/extract_options_spec.rb +2 -2
- data/spec/gorillib/builder_spec.rb +187 -0
- data/spec/gorillib/collection_spec.rb +20 -0
- data/spec/gorillib/configurable_spec.rb +62 -0
- data/spec/{datetime → gorillib/datetime}/parse_spec.rb +3 -3
- data/spec/{datetime/flat_spec.rb → gorillib/datetime/to_flat_spec.rb} +4 -4
- data/spec/{enumerable → gorillib/enumerable}/sum_spec.rb +5 -5
- data/spec/gorillib/exception/raisers_spec.rb +60 -0
- data/spec/{hash → gorillib/hash}/compact_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/deep_compact_spec.rb +3 -3
- data/spec/{hash → gorillib/hash}/deep_merge_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/keys_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/reverse_merge_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/slice_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/zip_spec.rb +2 -2
- data/spec/{hashlike → gorillib/hashlike}/behave_same_as_hash_spec.rb +6 -3
- data/spec/{hashlike → gorillib/hashlike}/deep_hash_spec.rb +2 -2
- data/spec/{hashlike → gorillib/hashlike}/hashlike_behavior_spec.rb +32 -30
- data/spec/{hashlike → gorillib/hashlike}/hashlike_via_accessors_spec.rb +3 -3
- data/spec/{hashlike_spec.rb → gorillib/hashlike_spec.rb} +3 -3
- data/spec/{logger → gorillib/logger}/log_spec.rb +2 -2
- data/spec/{metaprogramming → gorillib/metaprogramming}/aliasing_spec.rb +3 -3
- data/spec/{metaprogramming → gorillib/metaprogramming}/class_attribute_spec.rb +3 -3
- data/spec/{metaprogramming → gorillib/metaprogramming}/delegation_spec.rb +3 -3
- data/spec/{metaprogramming → gorillib/metaprogramming}/singleton_class_spec.rb +3 -3
- data/spec/gorillib/model/record/defaults_spec.rb +108 -0
- data/spec/gorillib/model/record/factories_spec.rb +321 -0
- data/spec/gorillib/model/record/overlay_spec.rb +46 -0
- data/spec/gorillib/model/serialization_spec.rb +48 -0
- data/spec/gorillib/model_spec.rb +281 -0
- data/spec/{numeric → gorillib/numeric}/clamp_spec.rb +2 -2
- data/spec/{object → gorillib/object}/blank_spec.rb +2 -2
- data/spec/{object → gorillib/object}/try_dup_spec.rb +2 -2
- data/spec/{object → gorillib/object}/try_spec.rb +3 -2
- data/spec/gorillib/pathname_spec.rb +114 -0
- data/spec/{string → gorillib/string}/constantize_spec.rb +2 -2
- data/spec/{string → gorillib/string}/human_spec.rb +2 -2
- data/spec/{string → gorillib/string}/inflections_spec.rb +4 -3
- data/spec/{string → gorillib/string}/inflector_test_cases.rb +0 -0
- data/spec/{string → gorillib/string}/truncate_spec.rb +4 -10
- data/spec/gorillib/type/extended_spec.rb +120 -0
- data/spec/gorillib/utils/capture_output_spec.rb +71 -0
- data/spec/spec_helper.rb +8 -11
- data/spec/support/gorillib_test_helpers.rb +66 -0
- data/spec/support/hashlike_fuzzing_helper.rb +31 -33
- data/spec/support/hashlike_helper.rb +3 -3
- data/spec/support/model_test_helpers.rb +81 -0
- data/spec/support/shared_examples/included_module.rb +20 -0
- metadata +177 -158
- data/lib/gorillib/array/average.rb +0 -13
- data/lib/gorillib/array/sorted_median.rb +0 -11
- data/lib/gorillib/array/sorted_percentile.rb +0 -11
- data/lib/gorillib/array/sorted_sample.rb +0 -12
- data/lib/gorillib/dsl_object.rb +0 -64
- data/lib/gorillib/hash/indifferent_access.rb +0 -207
- data/lib/gorillib/hash/tree_merge.rb +0 -4
- data/lib/gorillib/hashlike/tree_merge.rb +0 -49
- data/lib/gorillib/metaprogramming/cattr_accessor.rb +0 -79
- data/lib/gorillib/metaprogramming/mattr_accessor.rb +0 -61
- data/lib/gorillib/receiver/active_model_shim.rb +0 -32
- data/lib/gorillib/receiver/acts_as_hash.rb +0 -195
- data/lib/gorillib/receiver/acts_as_loadable.rb +0 -42
- data/lib/gorillib/receiver/locale/en.yml +0 -27
- data/lib/gorillib/receiver/tree_diff.rb +0 -74
- data/lib/gorillib/receiver/validations.rb +0 -30
- data/lib/gorillib/receiver.rb +0 -402
- data/lib/gorillib/receiver_model.rb +0 -21
- data/lib/gorillib/struct/acts_as_hash.rb +0 -108
- data/notes/fancy_hashes_and_receivers.textile +0 -120
- data/notes/hash_rdocs.textile +0 -97
- data/spec/array/average_spec.rb +0 -24
- data/spec/array/sorted_median_spec.rb +0 -18
- data/spec/array/sorted_percentile_spec.rb +0 -24
- data/spec/array/sorted_sample_spec.rb +0 -28
- data/spec/dsl_object_spec.rb +0 -99
- data/spec/hash/indifferent_access_spec.rb +0 -391
- data/spec/metaprogramming/cattr_accessor_spec.rb +0 -43
- data/spec/metaprogramming/mattr_accessor_spec.rb +0 -45
- data/spec/receiver/acts_as_hash_spec.rb +0 -295
- data/spec/receiver_spec.rb +0 -551
- data/spec/struct/acts_as_hash_fuzz_spec.rb +0 -71
- data/spec/struct/acts_as_hash_spec.rb +0 -422
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'gorillib/exception/raisers'
|
3
|
+
|
4
|
+
module Gorillib
|
5
|
+
module Pathref
|
6
|
+
ROOT_PATHS = Hash.new unless defined?(ROOT_PATHS)
|
7
|
+
|
8
|
+
extend self
|
9
|
+
|
10
|
+
def register_path(handle, *pathsegs)
|
11
|
+
ArgumentError.arity_at_least!(pathsegs, 1)
|
12
|
+
ROOT_PATHS[handle] = pathsegs
|
13
|
+
end
|
14
|
+
|
15
|
+
def register_paths(pairs = {})
|
16
|
+
pairs.each_pair{ |handle, pathsegs| register_path(handle, *pathsegs) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def unregister_path handle
|
20
|
+
ROOT_PATHS.delete handle
|
21
|
+
end
|
22
|
+
|
23
|
+
# Expand a path with late-evaluated segments.
|
24
|
+
# Calls expand_path -- '~' becomes $HOME, '..' is expanded, etc.
|
25
|
+
#
|
26
|
+
# @example A symbol represents a segment to expand
|
27
|
+
# Pathname.register_path(:conf_dir, '/etc/delorean')
|
28
|
+
# Pathname.path_to(:conf_dir) # '/etc/delorean'
|
29
|
+
# Pathname.path_to(:conf_dir, modacity.conf) # '/etc/delorean/modacity.conf'
|
30
|
+
#
|
31
|
+
# @example References aren't expanded until they're read
|
32
|
+
# Pathname.register_path(:conf_dir, '/etc/delorean')
|
33
|
+
# Pathname.register_path(:modacity, :conf_dir, 'modacity.conf')
|
34
|
+
# Pathname.path_to(:modacity) # '/etc/delorean/modacity.conf'
|
35
|
+
# # if we change the conf_dir, everything under it changes as well
|
36
|
+
# Pathname.register_path(:conf_dir, '~/.delorean.d')
|
37
|
+
# Pathname.path_to(:modacity) # '/home/flip/delorean.d/modacity.conf'
|
38
|
+
#
|
39
|
+
# @example References can be relative, and can hold symbols themselves
|
40
|
+
# Pathname.register_path(:conf_dir, '/etc', :appname, :environment)
|
41
|
+
# Pathname.register_path(:appname, 'happy_app')
|
42
|
+
# Pathname.register_path(:environment, 'dev')
|
43
|
+
# Pathname.path_to(:conf_dir) # '/etc/happy_app/dev'
|
44
|
+
#
|
45
|
+
# @param [Array<[String,Symbol]>] pathsegs
|
46
|
+
# any mixture of strings (literal sub-paths) and symbols (interpreted as references)
|
47
|
+
# @return [Pathname] A single expanded Pathname
|
48
|
+
#
|
49
|
+
def path_to(*pathsegs)
|
50
|
+
relative_path_to(*pathsegs).expand_path
|
51
|
+
end
|
52
|
+
|
53
|
+
# Expand a path with late-evaluated segments
|
54
|
+
# @see `.path_to`
|
55
|
+
#
|
56
|
+
# Calls cleanpath (removing `//` double slashes and useless `..`s), but does
|
57
|
+
# not reference the filesystem or make paths absolute
|
58
|
+
#
|
59
|
+
def relative_path_to(*pathsegs)
|
60
|
+
ArgumentError.arity_at_least!(pathsegs, 1)
|
61
|
+
pathsegs = pathsegs.map{|ps| expand_pathseg(ps) }.flatten
|
62
|
+
new(File.join(*pathsegs)).cleanpath(true)
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
# Recursively expand a path handle
|
67
|
+
# @return [Array<String>] an array of path segments, suitable for .join
|
68
|
+
def expand_pathseg(handle)
|
69
|
+
return handle unless handle.is_a?(Symbol)
|
70
|
+
pathsegs = ROOT_PATHS[handle] or raise ArgumentError, "Don't know how to expand path reference '#{handle.inspect}'."
|
71
|
+
pathsegs.map{|ps| expand_pathseg(ps) }.flatten
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Pathname
|
77
|
+
extend Gorillib::Pathref
|
78
|
+
end
|
File without changes
|
data/lib/gorillib/some.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
require 'gorillib/base'
|
2
1
|
require 'set'
|
3
2
|
require 'time'
|
4
3
|
require 'date'
|
5
|
-
require '
|
6
|
-
|
7
|
-
require 'gorillib/
|
8
|
-
|
9
|
-
require 'gorillib/
|
10
|
-
require 'gorillib/
|
11
|
-
require 'gorillib/
|
12
|
-
require 'gorillib/
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
require 'gorillib/base'
|
7
|
+
|
8
|
+
require 'gorillib/pathname'
|
9
|
+
require 'gorillib/string/simple_inflector'
|
10
|
+
require 'gorillib/string/inflections'
|
11
|
+
require 'gorillib/string/constantize'
|
12
|
+
require 'gorillib/hash/mash'
|
13
|
+
require 'gorillib/metaprogramming/delegation'
|
14
|
+
require 'gorillib/metaprogramming/concern'
|
@@ -1,21 +1,28 @@
|
|
1
|
+
require 'gorillib/string/inflector'
|
1
2
|
class String
|
2
3
|
|
3
|
-
#
|
4
|
+
# +constantize+ tries to find a declared constant with the name specified
|
4
5
|
# in the string. It raises a NameError when the name is not in CamelCase
|
5
|
-
# or is not initialized.
|
6
|
-
#
|
7
|
-
# @example
|
8
|
-
# "Module".constantize #=> Module
|
9
|
-
# "Class".constantize #=> Class
|
10
|
-
#
|
11
|
-
# This is the extlib version of String#constantize, which has different
|
12
|
-
# behavior wrt using lexical context: see active_support/inflector/methods.rb
|
6
|
+
# or is not initialized. See Gorillib::Inflector.constantize
|
13
7
|
#
|
8
|
+
# Examples
|
9
|
+
# "Module".constantize # => Module
|
10
|
+
# "Class".constantize # => Class
|
11
|
+
# "blargle".constantize # => NameError: wrong constant name blargle
|
14
12
|
def constantize
|
15
|
-
|
16
|
-
raise NameError, "#{self.inspect} is not a valid constant name!"
|
17
|
-
end
|
18
|
-
|
19
|
-
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
13
|
+
Gorillib::Inflector.constantize(self)
|
20
14
|
end unless method_defined?(:constantize)
|
15
|
+
|
16
|
+
# +safe_constantize+ tries to find a declared constant with the name specified
|
17
|
+
# in the string. It returns nil when the name is not in CamelCase
|
18
|
+
# or is not initialized. See Gorillib::Model::Inflector.safe_constantize
|
19
|
+
#
|
20
|
+
# Examples
|
21
|
+
# "Module".safe_constantize # => Module
|
22
|
+
# "Class".safe_constantize # => Class
|
23
|
+
# "blargle".safe_constantize # => nil
|
24
|
+
def safe_constantize
|
25
|
+
Gorillib::Inflector.safe_constantize(self)
|
26
|
+
end unless method_defined?(:safe_constantize)
|
27
|
+
|
21
28
|
end
|
@@ -1,78 +1,8 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
# "ScaleScore".underscore # => "scale_score"
|
4
|
-
#
|
5
|
-
# This doesn't define the full set of inflections -- only
|
6
|
-
#
|
7
|
-
# * camelize
|
8
|
-
# * snakeize
|
9
|
-
# * underscore
|
10
|
-
# * demodulize
|
11
|
-
#
|
12
|
-
class String
|
13
|
-
|
14
|
-
# By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
|
15
|
-
# is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase.
|
16
|
-
#
|
17
|
-
# +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
|
18
|
-
#
|
19
|
-
# @example:
|
20
|
-
# "active_record".camelize # => "ActiveRecord"
|
21
|
-
# "active_record".camelize(:lower) # => "activeRecord"
|
22
|
-
# "active_record/errors".camelize # => "ActiveRecord::Errors"
|
23
|
-
# "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
|
24
|
-
#
|
25
|
-
# As a rule of thumb you can think of +camelize+ as the inverse of +underscore+,
|
26
|
-
# though there are cases where that does not hold:
|
27
|
-
#
|
28
|
-
# "SSLError".underscore.camelize # => "SslError"
|
29
|
-
#
|
30
|
-
def camelize(first_letter = :upper)
|
31
|
-
camelized = self.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
32
|
-
(first_letter == :lower) ? (self[0..0].downcase + camelized[1..-1]) : camelized
|
33
|
-
end unless method_defined?(:camelize)
|
34
|
-
|
35
|
-
# Converts strings to snakeCase, also known as lowerCamelCase.
|
36
|
-
#
|
37
|
-
# +snakeize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
|
38
|
-
#
|
39
|
-
# @example:
|
40
|
-
# "active_record".snakeize # => "activeRecord"
|
41
|
-
# "active_record/errors".snakeize # => "activeRecord::Errors"
|
42
|
-
#
|
43
|
-
def snakeize
|
44
|
-
camelize :lower
|
45
|
-
end unless method_defined?(:snakeize)
|
46
|
-
|
47
|
-
# Makes an underscored, lowercase form from the expression in the string.
|
48
|
-
#
|
49
|
-
# +underscore+ will also change '::' to '/' to convert namespaces to paths.
|
50
|
-
#
|
51
|
-
# Examples:
|
52
|
-
# "ActiveRecord".underscore # => "active_record"
|
53
|
-
# "ActiveRecord::Errors".underscore # => active_record/errors
|
54
|
-
#
|
55
|
-
# As a rule of thumb you can think of +underscore+ as the inverse of +camelize+,
|
56
|
-
# though there are cases where that does not hold:
|
57
|
-
#
|
58
|
-
# "SSLError".underscore.camelize # => "SslError"
|
59
|
-
def underscore
|
60
|
-
word = self.dup
|
61
|
-
word.gsub!(/::/, '/')
|
62
|
-
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
63
|
-
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
64
|
-
word.tr!("-", "_")
|
65
|
-
word.downcase!
|
66
|
-
word
|
67
|
-
end unless method_defined?(:underscore)
|
68
|
-
|
69
|
-
# Removes the module part from the expression in the string
|
70
|
-
#
|
71
|
-
# @example
|
72
|
-
# "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
|
73
|
-
# "Inflections".demodulize #=> "Inflections"
|
74
|
-
def demodulize
|
75
|
-
self.gsub(/^.*::/, '')
|
76
|
-
end unless method_defined?(:demodulize)
|
1
|
+
require 'gorillib/string/inflector'
|
77
2
|
|
3
|
+
class String
|
4
|
+
def camelize(*args) Gorillib::Inflector.camelize(self, *args) ; end
|
5
|
+
def snakeize(*args) Gorillib::Inflector.snakeize(self, *args) ; end
|
6
|
+
def underscore(*args) Gorillib::Inflector.underscore(self, *args) ; end
|
7
|
+
def demodulize(*args) Gorillib::Inflector.demodulize(self, *args) ; end
|
78
8
|
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
module Gorillib ; end
|
2
|
+
|
3
|
+
# String inflections define new methods on the String class to transform names for different purposes.
|
4
|
+
#
|
5
|
+
# "ScaleScore".underscore # => "scale_score"
|
6
|
+
#
|
7
|
+
# This doesn't define the full set of inflections -- only
|
8
|
+
#
|
9
|
+
# * camelize
|
10
|
+
# * snakeize
|
11
|
+
# * underscore
|
12
|
+
# * demodulize
|
13
|
+
#
|
14
|
+
module Gorillib::Inflector
|
15
|
+
extend self
|
16
|
+
|
17
|
+
# By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
|
18
|
+
# is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase.
|
19
|
+
#
|
20
|
+
# +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
|
21
|
+
#
|
22
|
+
# @example:
|
23
|
+
# "active_record".camelize # => "ActiveRecord"
|
24
|
+
# "active_record".camelize(:lower) # => "activeRecord"
|
25
|
+
# "active_record/errors".camelize # => "ActiveRecord::Errors"
|
26
|
+
# "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
|
27
|
+
#
|
28
|
+
# As a rule of thumb you can think of +camelize+ as the inverse of +underscore+,
|
29
|
+
# though there are cases where that does not hold:
|
30
|
+
#
|
31
|
+
# "SSLError".underscore.camelize # => "SslError"
|
32
|
+
#
|
33
|
+
def camelize(str, first_letter = :upper)
|
34
|
+
camelized = str.gsub(/\/(.?)/){ "::#{ $1.upcase }" }.gsub(/(?:^|_)(.)/){ $1.upcase }
|
35
|
+
(first_letter == :lower) ? (str[0..0].downcase + camelized[1..-1]) : camelized
|
36
|
+
end
|
37
|
+
|
38
|
+
# Converts strings to snakeCase, also known as lowerCamelCase.
|
39
|
+
#
|
40
|
+
# +snakeize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
|
41
|
+
#
|
42
|
+
# @example:
|
43
|
+
# "active_record".snakeize # => "activeRecord"
|
44
|
+
# "active_record/errors".snakeize # => "activeRecord::Errors"
|
45
|
+
#
|
46
|
+
def snakeize(str)
|
47
|
+
camelize(str, :lower)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Makes an underscored, lowercase form from the expression in the string.
|
51
|
+
#
|
52
|
+
# +underscore+ will also change '::' to '/' to convert namespaces to paths.
|
53
|
+
#
|
54
|
+
# Examples:
|
55
|
+
# "ActiveRecord".underscore # => "active_record"
|
56
|
+
# "ActiveRecord::Errors".underscore # => active_record/errors
|
57
|
+
#
|
58
|
+
# As a rule of thumb you can think of +underscore+ as the inverse of +camelize+,
|
59
|
+
# though there are cases where that does not hold:
|
60
|
+
#
|
61
|
+
# "SSLError".underscore.camelize # => "SslError"
|
62
|
+
def underscore(str)
|
63
|
+
word = str.dup
|
64
|
+
word.gsub!(/::/, '/')
|
65
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
66
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
67
|
+
word.tr!("-", "_")
|
68
|
+
word.downcase!
|
69
|
+
word
|
70
|
+
end
|
71
|
+
|
72
|
+
# Replaces underscores with dashes in the string.
|
73
|
+
#
|
74
|
+
# Example:
|
75
|
+
# "puni_puni" # => "puni-puni"
|
76
|
+
def dasherize(underscored_word)
|
77
|
+
underscored_word.gsub(/_/, '-')
|
78
|
+
end
|
79
|
+
|
80
|
+
# Removes the module part from the expression in the string:
|
81
|
+
#
|
82
|
+
# @example
|
83
|
+
# "Gorillib::Inflections".demodulize #=> "Inflections"
|
84
|
+
# "Inflections".demodulize #=> "Inflections"
|
85
|
+
#
|
86
|
+
# See also +deconstantize+.
|
87
|
+
def demodulize(str)
|
88
|
+
str.gsub(/^.*::/, '')
|
89
|
+
end
|
90
|
+
|
91
|
+
# Removes the rightmost segment from the constant expression in the string:
|
92
|
+
#
|
93
|
+
# "Net::HTTP".deconstantize # => "Net"
|
94
|
+
# "::Net::HTTP".deconstantize # => "::Net"
|
95
|
+
# "String".deconstantize # => ""
|
96
|
+
# "::String".deconstantize # => ""
|
97
|
+
# "".deconstantize # => ""
|
98
|
+
#
|
99
|
+
# See also +demodulize+.
|
100
|
+
def deconstantize(path)
|
101
|
+
path.to_s[0...(path.rindex('::') || 0)] # implementation based on the one in facets' Module#spacename
|
102
|
+
end
|
103
|
+
|
104
|
+
# Constantize tries to find a declared constant with the name specified
|
105
|
+
# in the string. It raises a NameError when the name is not in CamelCase
|
106
|
+
# or is not initialized.
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
# "Module".constantize #=> Module
|
110
|
+
# "Class".constantize #=> Class
|
111
|
+
#
|
112
|
+
# This is the extlib version of String#constantize, which has different
|
113
|
+
# behavior wrt using lexical context: see active_support/inflector/methods.rb
|
114
|
+
#
|
115
|
+
def constantize(str)
|
116
|
+
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ str
|
117
|
+
raise NameError, "#{self.inspect} is not a valid constant name!"
|
118
|
+
end
|
119
|
+
|
120
|
+
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Tries to find a constant with the name specified in the argument string:
|
124
|
+
#
|
125
|
+
# "Module".safe_constantize # => Module
|
126
|
+
# "Test::Unit".safe_constantize # => Test::Unit
|
127
|
+
#
|
128
|
+
# The name is assumed to be the one of a top-level constant, no matter whether
|
129
|
+
# it starts with "::" or not. No lexical context is taken into account:
|
130
|
+
#
|
131
|
+
# C = 'outside'
|
132
|
+
# module M
|
133
|
+
# C = 'inside'
|
134
|
+
# C # => 'inside'
|
135
|
+
# "C".safe_constantize # => 'outside', same as ::C
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# nil is returned when the name is not in CamelCase or the constant (or part of it) is
|
139
|
+
# unknown.
|
140
|
+
#
|
141
|
+
# "blargle".safe_constantize # => nil
|
142
|
+
# "UnknownModule".safe_constantize # => nil
|
143
|
+
# "UnknownModule::Foo::Bar".safe_constantize # => nil
|
144
|
+
#
|
145
|
+
def safe_constantize(camel_cased_word)
|
146
|
+
begin
|
147
|
+
constantize(camel_cased_word)
|
148
|
+
rescue NameError => e
|
149
|
+
raise unless e.message =~ /uninitialized constant #{const_regexp(camel_cased_word)}$/ ||
|
150
|
+
e.name.to_s == camel_cased_word.to_s
|
151
|
+
rescue ArgumentError => e
|
152
|
+
raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Turns a number into an ordinal string used to denote the position in an
|
157
|
+
# ordered sequence such as 1st, 2nd, 3rd, 4th.
|
158
|
+
#
|
159
|
+
# Examples:
|
160
|
+
# ordinalize(1) # => "1st"
|
161
|
+
# ordinalize(2) # => "2nd"
|
162
|
+
# ordinalize(1002) # => "1002nd"
|
163
|
+
# ordinalize(1003) # => "1003rd"
|
164
|
+
# ordinalize(-11) # => "-11th"
|
165
|
+
# ordinalize(-1021) # => "-1021st"
|
166
|
+
def ordinalize(number)
|
167
|
+
if (11..13).include?(number.to_i.abs % 100)
|
168
|
+
"#{number}th"
|
169
|
+
else
|
170
|
+
case number.to_i.abs % 10
|
171
|
+
when 1; "#{number}st"
|
172
|
+
when 2; "#{number}nd"
|
173
|
+
when 3; "#{number}rd"
|
174
|
+
else "#{number}th"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
# Mount a regular expression that will match part by part of the constant.
|
182
|
+
# For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)?
|
183
|
+
def const_regexp(camel_cased_word) #:nodoc:
|
184
|
+
parts = camel_cased_word.split("::")
|
185
|
+
last = parts.pop
|
186
|
+
|
187
|
+
parts.reverse.inject(last) do |acc, part|
|
188
|
+
part.empty? ? acc : "#{part}(::#{acc})?"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|