gorillib 0.1.11 → 0.4.0pre
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/.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
|