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.
Files changed (143) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +1 -2
  3. data/.yardopts +9 -0
  4. data/{CHANGELOG.textile → CHANGELOG.md} +35 -9
  5. data/Gemfile +21 -14
  6. data/Guardfile +19 -0
  7. data/{LICENSE.textile → LICENSE.md} +43 -29
  8. data/README.md +47 -52
  9. data/Rakefile +31 -30
  10. data/TODO.md +32 -0
  11. data/VERSION +1 -1
  12. data/examples/builder/ironfan.rb +133 -0
  13. data/examples/model/simple.rb +17 -0
  14. data/gorillib.gemspec +106 -86
  15. data/lib/alt/kernel/call_stack.rb +56 -0
  16. data/lib/gorillib/array/wrap.rb +53 -0
  17. data/lib/gorillib/base.rb +3 -3
  18. data/lib/gorillib/builder/field.rb +5 -0
  19. data/lib/gorillib/builder.rb +260 -0
  20. data/lib/gorillib/collection/has_collection.rb +31 -0
  21. data/lib/gorillib/collection.rb +129 -0
  22. data/lib/gorillib/configurable.rb +28 -0
  23. data/lib/gorillib/datetime/{flat.rb → to_flat.rb} +0 -0
  24. data/lib/gorillib/exception/confidence.rb +17 -0
  25. data/lib/gorillib/exception/raisers.rb +78 -0
  26. data/lib/gorillib/hash/mash.rb +202 -0
  27. data/lib/gorillib/hashlike/slice.rb +53 -19
  28. data/lib/gorillib/hashlike.rb +5 -3
  29. data/lib/gorillib/io/system_helpers.rb +30 -0
  30. data/lib/gorillib/logger/log.rb +18 -0
  31. data/lib/gorillib/metaprogramming/concern.rb +124 -0
  32. data/lib/gorillib/model/active_model_conversion.rb +68 -0
  33. data/lib/gorillib/model/active_model_naming.rb +87 -0
  34. data/lib/gorillib/model/active_model_shim.rb +33 -0
  35. data/lib/gorillib/model/base.rb +341 -0
  36. data/lib/gorillib/model/defaults.rb +71 -0
  37. data/lib/gorillib/model/errors.rb +14 -0
  38. data/lib/gorillib/model/factories.rb +372 -0
  39. data/lib/gorillib/model/field.rb +146 -0
  40. data/lib/gorillib/model/named_schema.rb +53 -0
  41. data/lib/gorillib/{struct/hashlike_iteration.rb → model/overlay.rb} +0 -0
  42. data/lib/gorillib/model/record_schema.rb +9 -0
  43. data/lib/gorillib/model/serialization.rb +23 -0
  44. data/lib/gorillib/model/validate.rb +22 -0
  45. data/lib/gorillib/model.rb +23 -0
  46. data/lib/gorillib/pathname.rb +78 -0
  47. data/lib/gorillib/{serialization.rb → serialization/to_wire.rb} +0 -0
  48. data/lib/gorillib/some.rb +11 -9
  49. data/lib/gorillib/string/constantize.rb +21 -14
  50. data/lib/gorillib/string/inflections.rb +6 -76
  51. data/lib/gorillib/string/inflector.rb +192 -0
  52. data/lib/gorillib/string/simple_inflector.rb +267 -0
  53. data/lib/gorillib/type/extended.rb +52 -0
  54. data/lib/gorillib/utils/capture_output.rb +28 -0
  55. data/lib/gorillib/utils/console.rb +131 -0
  56. data/lib/gorillib/utils/nuke_constants.rb +9 -0
  57. data/lib/gorillib/utils/stub_module.rb +33 -0
  58. data/spec/examples/builder/ironfan_spec.rb +37 -0
  59. data/spec/extlib/hash_spec.rb +64 -0
  60. data/spec/extlib/mash_spec.rb +312 -0
  61. data/spec/{array → gorillib/array}/compact_blank_spec.rb +2 -2
  62. data/spec/{array → gorillib/array}/extract_options_spec.rb +2 -2
  63. data/spec/gorillib/builder_spec.rb +187 -0
  64. data/spec/gorillib/collection_spec.rb +20 -0
  65. data/spec/gorillib/configurable_spec.rb +62 -0
  66. data/spec/{datetime → gorillib/datetime}/parse_spec.rb +3 -3
  67. data/spec/{datetime/flat_spec.rb → gorillib/datetime/to_flat_spec.rb} +4 -4
  68. data/spec/{enumerable → gorillib/enumerable}/sum_spec.rb +5 -5
  69. data/spec/gorillib/exception/raisers_spec.rb +60 -0
  70. data/spec/{hash → gorillib/hash}/compact_spec.rb +2 -2
  71. data/spec/{hash → gorillib/hash}/deep_compact_spec.rb +3 -3
  72. data/spec/{hash → gorillib/hash}/deep_merge_spec.rb +2 -2
  73. data/spec/{hash → gorillib/hash}/keys_spec.rb +2 -2
  74. data/spec/{hash → gorillib/hash}/reverse_merge_spec.rb +2 -2
  75. data/spec/{hash → gorillib/hash}/slice_spec.rb +2 -2
  76. data/spec/{hash → gorillib/hash}/zip_spec.rb +2 -2
  77. data/spec/{hashlike → gorillib/hashlike}/behave_same_as_hash_spec.rb +6 -3
  78. data/spec/{hashlike → gorillib/hashlike}/deep_hash_spec.rb +2 -2
  79. data/spec/{hashlike → gorillib/hashlike}/hashlike_behavior_spec.rb +32 -30
  80. data/spec/{hashlike → gorillib/hashlike}/hashlike_via_accessors_spec.rb +3 -3
  81. data/spec/{hashlike_spec.rb → gorillib/hashlike_spec.rb} +3 -3
  82. data/spec/{logger → gorillib/logger}/log_spec.rb +2 -2
  83. data/spec/{metaprogramming → gorillib/metaprogramming}/aliasing_spec.rb +3 -3
  84. data/spec/{metaprogramming → gorillib/metaprogramming}/class_attribute_spec.rb +3 -3
  85. data/spec/{metaprogramming → gorillib/metaprogramming}/delegation_spec.rb +3 -3
  86. data/spec/{metaprogramming → gorillib/metaprogramming}/singleton_class_spec.rb +3 -3
  87. data/spec/gorillib/model/record/defaults_spec.rb +108 -0
  88. data/spec/gorillib/model/record/factories_spec.rb +321 -0
  89. data/spec/gorillib/model/record/overlay_spec.rb +46 -0
  90. data/spec/gorillib/model/serialization_spec.rb +48 -0
  91. data/spec/gorillib/model_spec.rb +281 -0
  92. data/spec/{numeric → gorillib/numeric}/clamp_spec.rb +2 -2
  93. data/spec/{object → gorillib/object}/blank_spec.rb +2 -2
  94. data/spec/{object → gorillib/object}/try_dup_spec.rb +2 -2
  95. data/spec/{object → gorillib/object}/try_spec.rb +3 -2
  96. data/spec/gorillib/pathname_spec.rb +114 -0
  97. data/spec/{string → gorillib/string}/constantize_spec.rb +2 -2
  98. data/spec/{string → gorillib/string}/human_spec.rb +2 -2
  99. data/spec/{string → gorillib/string}/inflections_spec.rb +4 -3
  100. data/spec/{string → gorillib/string}/inflector_test_cases.rb +0 -0
  101. data/spec/{string → gorillib/string}/truncate_spec.rb +4 -10
  102. data/spec/gorillib/type/extended_spec.rb +120 -0
  103. data/spec/gorillib/utils/capture_output_spec.rb +71 -0
  104. data/spec/spec_helper.rb +8 -11
  105. data/spec/support/gorillib_test_helpers.rb +66 -0
  106. data/spec/support/hashlike_fuzzing_helper.rb +31 -33
  107. data/spec/support/hashlike_helper.rb +3 -3
  108. data/spec/support/model_test_helpers.rb +81 -0
  109. data/spec/support/shared_examples/included_module.rb +20 -0
  110. metadata +177 -158
  111. data/lib/gorillib/array/average.rb +0 -13
  112. data/lib/gorillib/array/sorted_median.rb +0 -11
  113. data/lib/gorillib/array/sorted_percentile.rb +0 -11
  114. data/lib/gorillib/array/sorted_sample.rb +0 -12
  115. data/lib/gorillib/dsl_object.rb +0 -64
  116. data/lib/gorillib/hash/indifferent_access.rb +0 -207
  117. data/lib/gorillib/hash/tree_merge.rb +0 -4
  118. data/lib/gorillib/hashlike/tree_merge.rb +0 -49
  119. data/lib/gorillib/metaprogramming/cattr_accessor.rb +0 -79
  120. data/lib/gorillib/metaprogramming/mattr_accessor.rb +0 -61
  121. data/lib/gorillib/receiver/active_model_shim.rb +0 -32
  122. data/lib/gorillib/receiver/acts_as_hash.rb +0 -195
  123. data/lib/gorillib/receiver/acts_as_loadable.rb +0 -42
  124. data/lib/gorillib/receiver/locale/en.yml +0 -27
  125. data/lib/gorillib/receiver/tree_diff.rb +0 -74
  126. data/lib/gorillib/receiver/validations.rb +0 -30
  127. data/lib/gorillib/receiver.rb +0 -402
  128. data/lib/gorillib/receiver_model.rb +0 -21
  129. data/lib/gorillib/struct/acts_as_hash.rb +0 -108
  130. data/notes/fancy_hashes_and_receivers.textile +0 -120
  131. data/notes/hash_rdocs.textile +0 -97
  132. data/spec/array/average_spec.rb +0 -24
  133. data/spec/array/sorted_median_spec.rb +0 -18
  134. data/spec/array/sorted_percentile_spec.rb +0 -24
  135. data/spec/array/sorted_sample_spec.rb +0 -28
  136. data/spec/dsl_object_spec.rb +0 -99
  137. data/spec/hash/indifferent_access_spec.rb +0 -391
  138. data/spec/metaprogramming/cattr_accessor_spec.rb +0 -43
  139. data/spec/metaprogramming/mattr_accessor_spec.rb +0 -45
  140. data/spec/receiver/acts_as_hash_spec.rb +0 -295
  141. data/spec/receiver_spec.rb +0 -551
  142. data/spec/struct/acts_as_hash_fuzz_spec.rb +0 -71
  143. 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
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 'gorillib/array/compact_blank'
6
- require 'gorillib/hash/compact'
7
- require 'gorillib/enumerable/sum'
8
- require 'gorillib/datetime/flat'
9
- require 'gorillib/datetime/parse'
10
- require 'gorillib/hash/zip'
11
- require 'gorillib/hash/slice'
12
- require 'gorillib/hash/keys'
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
- # Constantize tries to find a declared constant with the name specified
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
- unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
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
- # String inflections define new methods on the String class to transform names for different purposes.
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