activesupport-refinements 0.0.1

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 (120) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +32 -0
  5. data/Rakefile +1 -0
  6. data/activesupport-refinements.gemspec +21 -0
  7. data/lib/active_support/refinements/core_ext/array.rb +7 -0
  8. data/lib/active_support/refinements/core_ext/array/access.rb +56 -0
  9. data/lib/active_support/refinements/core_ext/array/conversions.rb +224 -0
  10. data/lib/active_support/refinements/core_ext/array/extract_options.rb +31 -0
  11. data/lib/active_support/refinements/core_ext/array/grouping.rb +101 -0
  12. data/lib/active_support/refinements/core_ext/array/prepend_and_append.rb +9 -0
  13. data/lib/active_support/refinements/core_ext/array/uniq_by.rb +21 -0
  14. data/lib/active_support/refinements/core_ext/array/wrap.rb +48 -0
  15. data/lib/active_support/refinements/core_ext/benchmark.rb +7 -0
  16. data/lib/active_support/refinements/core_ext/big_decimal.rb +1 -0
  17. data/lib/active_support/refinements/core_ext/big_decimal/conversions.rb +32 -0
  18. data/lib/active_support/refinements/core_ext/class.rb +4 -0
  19. data/lib/active_support/refinements/core_ext/class/attribute.rb +119 -0
  20. data/lib/active_support/refinements/core_ext/class/attribute_accessors.rb +172 -0
  21. data/lib/active_support/refinements/core_ext/class/delegating_attributes.rb +42 -0
  22. data/lib/active_support/refinements/core_ext/class/subclasses.rb +44 -0
  23. data/lib/active_support/refinements/core_ext/date.rb +5 -0
  24. data/lib/active_support/refinements/core_ext/date/acts_like.rb +10 -0
  25. data/lib/active_support/refinements/core_ext/date/calculations.rb +123 -0
  26. data/lib/active_support/refinements/core_ext/date/conversions.rb +86 -0
  27. data/lib/active_support/refinements/core_ext/date/zones.rb +17 -0
  28. data/lib/active_support/refinements/core_ext/date_and_time/calculations.rb +232 -0
  29. data/lib/active_support/refinements/core_ext/date_time.rb +4 -0
  30. data/lib/active_support/refinements/core_ext/date_time/acts_like.rb +15 -0
  31. data/lib/active_support/refinements/core_ext/date_time/calculations.rb +143 -0
  32. data/lib/active_support/refinements/core_ext/date_time/conversions.rb +93 -0
  33. data/lib/active_support/refinements/core_ext/date_time/zones.rb +26 -0
  34. data/lib/active_support/refinements/core_ext/enumerable.rb +82 -0
  35. data/lib/active_support/refinements/core_ext/exception.rb +5 -0
  36. data/lib/active_support/refinements/core_ext/file.rb +1 -0
  37. data/lib/active_support/refinements/core_ext/file/atomic.rb +60 -0
  38. data/lib/active_support/refinements/core_ext/hash.rb +8 -0
  39. data/lib/active_support/refinements/core_ext/hash/conversions.rb +161 -0
  40. data/lib/active_support/refinements/core_ext/hash/deep_merge.rb +29 -0
  41. data/lib/active_support/refinements/core_ext/hash/diff.rb +15 -0
  42. data/lib/active_support/refinements/core_ext/hash/except.rb +17 -0
  43. data/lib/active_support/refinements/core_ext/hash/indifferent_access.rb +24 -0
  44. data/lib/active_support/refinements/core_ext/hash/keys.rb +140 -0
  45. data/lib/active_support/refinements/core_ext/hash/reverse_merge.rb +24 -0
  46. data/lib/active_support/refinements/core_ext/hash/slice.rb +42 -0
  47. data/lib/active_support/refinements/core_ext/integer.rb +3 -0
  48. data/lib/active_support/refinements/core_ext/integer/inflections.rb +31 -0
  49. data/lib/active_support/refinements/core_ext/integer/multiple.rb +12 -0
  50. data/lib/active_support/refinements/core_ext/integer/time.rb +43 -0
  51. data/lib/active_support/refinements/core_ext/kernel.rb +4 -0
  52. data/lib/active_support/refinements/core_ext/kernel/agnostics.rb +13 -0
  53. data/lib/active_support/refinements/core_ext/kernel/debugger.rb +12 -0
  54. data/lib/active_support/refinements/core_ext/kernel/reporting.rb +97 -0
  55. data/lib/active_support/refinements/core_ext/kernel/singleton_class.rb +8 -0
  56. data/lib/active_support/refinements/core_ext/load_error.rb +27 -0
  57. data/lib/active_support/refinements/core_ext/logger.rb +86 -0
  58. data/lib/active_support/refinements/core_ext/module.rb +10 -0
  59. data/lib/active_support/refinements/core_ext/module/aliasing.rb +69 -0
  60. data/lib/active_support/refinements/core_ext/module/anonymous.rb +21 -0
  61. data/lib/active_support/refinements/core_ext/module/attr_internal.rb +40 -0
  62. data/lib/active_support/refinements/core_ext/module/attribute_accessors.rb +68 -0
  63. data/lib/active_support/refinements/core_ext/module/delegation.rb +172 -0
  64. data/lib/active_support/refinements/core_ext/module/deprecation.rb +27 -0
  65. data/lib/active_support/refinements/core_ext/module/introspection.rb +80 -0
  66. data/lib/active_support/refinements/core_ext/module/qualified_const.rb +54 -0
  67. data/lib/active_support/refinements/core_ext/module/reachable.rb +10 -0
  68. data/lib/active_support/refinements/core_ext/module/remove_method.rb +14 -0
  69. data/lib/active_support/refinements/core_ext/name_error.rb +20 -0
  70. data/lib/active_support/refinements/core_ext/numeric.rb +3 -0
  71. data/lib/active_support/refinements/core_ext/numeric/bytes.rb +46 -0
  72. data/lib/active_support/refinements/core_ext/numeric/conversions.rb +137 -0
  73. data/lib/active_support/refinements/core_ext/numeric/time.rb +81 -0
  74. data/lib/active_support/refinements/core_ext/object.rb +14 -0
  75. data/lib/active_support/refinements/core_ext/object/acts_like.rb +12 -0
  76. data/lib/active_support/refinements/core_ext/object/blank.rb +107 -0
  77. data/lib/active_support/refinements/core_ext/object/conversions.rb +4 -0
  78. data/lib/active_support/refinements/core_ext/object/deep_dup.rb +48 -0
  79. data/lib/active_support/refinements/core_ext/object/duplicable.rb +92 -0
  80. data/lib/active_support/refinements/core_ext/object/inclusion.rb +27 -0
  81. data/lib/active_support/refinements/core_ext/object/instance_variables.rb +30 -0
  82. data/lib/active_support/refinements/core_ext/object/to_json.rb +27 -0
  83. data/lib/active_support/refinements/core_ext/object/to_param.rb +60 -0
  84. data/lib/active_support/refinements/core_ext/object/to_query.rb +29 -0
  85. data/lib/active_support/refinements/core_ext/object/try.rb +72 -0
  86. data/lib/active_support/refinements/core_ext/object/with_options.rb +44 -0
  87. data/lib/active_support/refinements/core_ext/proc.rb +19 -0
  88. data/lib/active_support/refinements/core_ext/range.rb +3 -0
  89. data/lib/active_support/refinements/core_ext/range/conversions.rb +21 -0
  90. data/lib/active_support/refinements/core_ext/range/include_range.rb +23 -0
  91. data/lib/active_support/refinements/core_ext/range/overlaps.rb +10 -0
  92. data/lib/active_support/refinements/core_ext/regexp.rb +7 -0
  93. data/lib/active_support/refinements/core_ext/string.rb +13 -0
  94. data/lib/active_support/refinements/core_ext/string/access.rb +106 -0
  95. data/lib/active_support/refinements/core_ext/string/behavior.rb +8 -0
  96. data/lib/active_support/refinements/core_ext/string/conversions.rb +60 -0
  97. data/lib/active_support/refinements/core_ext/string/encoding.rb +10 -0
  98. data/lib/active_support/refinements/core_ext/string/exclude.rb +13 -0
  99. data/lib/active_support/refinements/core_ext/string/filters.rb +54 -0
  100. data/lib/active_support/refinements/core_ext/string/indent.rb +45 -0
  101. data/lib/active_support/refinements/core_ext/string/inflections.rb +214 -0
  102. data/lib/active_support/refinements/core_ext/string/inquiry.rb +15 -0
  103. data/lib/active_support/refinements/core_ext/string/multibyte.rb +58 -0
  104. data/lib/active_support/refinements/core_ext/string/output_safety.rb +194 -0
  105. data/lib/active_support/refinements/core_ext/string/starts_ends_with.rb +6 -0
  106. data/lib/active_support/refinements/core_ext/string/strip.rb +28 -0
  107. data/lib/active_support/refinements/core_ext/string/xchar.rb +18 -0
  108. data/lib/active_support/refinements/core_ext/time.rb +5 -0
  109. data/lib/active_support/refinements/core_ext/time/acts_like.rb +10 -0
  110. data/lib/active_support/refinements/core_ext/time/calculations.rb +251 -0
  111. data/lib/active_support/refinements/core_ext/time/conversions.rb +65 -0
  112. data/lib/active_support/refinements/core_ext/time/marshal.rb +30 -0
  113. data/lib/active_support/refinements/core_ext/time/zones.rb +98 -0
  114. data/lib/active_support/refinements/core_ext/uri.rb +28 -0
  115. data/lib/activesupport-refinements.rb +9 -0
  116. data/lib/activesupport-refinements/version.rb +5 -0
  117. data/refine_core_ext.rb +45 -0
  118. data/spec/hwia_spec.rb +15 -0
  119. data/spec/try_spec.rb +18 -0
  120. metadata +182 -0
@@ -0,0 +1,40 @@
1
+ module ModuleExt; end; module ModuleExt::AttrInternal
2
+ refine Module do
3
+ # Declares an attribute reader backed by an internally-named instance variable.
4
+ def attr_internal_reader(*attrs)
5
+ attrs.each {|attr_name| attr_internal_define(attr_name, :reader)}
6
+ end
7
+
8
+ # Declares an attribute writer backed by an internally-named instance variable.
9
+ def attr_internal_writer(*attrs)
10
+ attrs.each {|attr_name| attr_internal_define(attr_name, :writer)}
11
+ end
12
+
13
+ # Declares an attribute reader and writer backed by an internally-named instance
14
+ # variable.
15
+ def attr_internal_accessor(*attrs)
16
+ attr_internal_reader(*attrs)
17
+ attr_internal_writer(*attrs)
18
+ end
19
+ # alias_method :attr_internal, :attr_internal_accessor
20
+
21
+ class << self; attr_accessor :attr_internal_naming_format end
22
+ self.attr_internal_naming_format = '@_%s'
23
+
24
+ private
25
+ def attr_internal_ivar_name(attr)
26
+ Module.attr_internal_naming_format % attr
27
+ end
28
+
29
+ def attr_internal_define(attr_name, type)
30
+ internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '')
31
+ class_eval do # class_eval is necessary on 1.9 or else the methods a made private
32
+ # use native attr_* methods as they are faster on some Ruby implementations
33
+ send("attr_#{type}", internal_name)
34
+ end
35
+ attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
36
+ # alias_method attr_name, internal_name
37
+ remove_method internal_name
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,68 @@
1
+ module ModuleExt; end; module ModuleExt::AttributeAccessors
2
+ require 'active_support/refinements/core_ext/array/extract_options'
3
+
4
+ refine Module do
5
+ def mattr_reader(*syms)
6
+ options = syms.extract_options!
7
+ syms.each do |sym|
8
+ raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
9
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
10
+ @@#{sym} = nil unless defined? @@#{sym}
11
+
12
+ def self.#{sym}
13
+ @@#{sym}
14
+ end
15
+ EOS
16
+
17
+ unless options[:instance_reader] == false || options[:instance_accessor] == false
18
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
19
+ def #{sym}
20
+ @@#{sym}
21
+ end
22
+ EOS
23
+ end
24
+ end
25
+ end
26
+
27
+ def mattr_writer(*syms)
28
+ options = syms.extract_options!
29
+ syms.each do |sym|
30
+ raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
31
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
32
+ def self.#{sym}=(obj)
33
+ @@#{sym} = obj
34
+ end
35
+ EOS
36
+
37
+ unless options[:instance_writer] == false || options[:instance_accessor] == false
38
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
39
+ def #{sym}=(obj)
40
+ @@#{sym} = obj
41
+ end
42
+ EOS
43
+ end
44
+ end
45
+ end
46
+
47
+ # Extends the module object with module and instance accessors for class attributes,
48
+ # just like the native attr* accessors for instance attributes.
49
+ #
50
+ # module AppConfiguration
51
+ # mattr_accessor :google_api_key
52
+ #
53
+ # self.google_api_key = "123456789"
54
+ # end
55
+ #
56
+ # AppConfiguration.google_api_key # => "123456789"
57
+ # AppConfiguration.google_api_key = "overriding the api key!"
58
+ # AppConfiguration.google_api_key # => "overriding the api key!"
59
+ #
60
+ # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
61
+ # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
62
+ # To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
63
+ def mattr_accessor(*syms)
64
+ mattr_reader(*syms)
65
+ mattr_writer(*syms)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,172 @@
1
+ module ModuleExt; end; module ModuleExt::Delegation
2
+ refine Module do
3
+ # Provides a delegate class method to easily expose contained objects' public methods
4
+ # as your own. Pass one or more methods (specified as symbols or strings)
5
+ # and the name of the target object via the <tt>:to</tt> option (also a symbol
6
+ # or string). At least one method and the <tt>:to</tt> option are required.
7
+ #
8
+ # Delegation is particularly useful with Active Record associations:
9
+ #
10
+ # class Greeter < ActiveRecord::Base
11
+ # def hello
12
+ # 'hello'
13
+ # end
14
+ #
15
+ # def goodbye
16
+ # 'goodbye'
17
+ # end
18
+ # end
19
+ #
20
+ # class Foo < ActiveRecord::Base
21
+ # belongs_to :greeter
22
+ # delegate :hello, to: :greeter
23
+ # end
24
+ #
25
+ # Foo.new.hello # => "hello"
26
+ # Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
27
+ #
28
+ # Multiple delegates to the same target are allowed:
29
+ #
30
+ # class Foo < ActiveRecord::Base
31
+ # belongs_to :greeter
32
+ # delegate :hello, :goodbye, to: :greeter
33
+ # end
34
+ #
35
+ # Foo.new.goodbye # => "goodbye"
36
+ #
37
+ # Methods can be delegated to instance variables, class variables, or constants
38
+ # by providing them as a symbols:
39
+ #
40
+ # class Foo
41
+ # CONSTANT_ARRAY = [0,1,2,3]
42
+ # @@class_array = [4,5,6,7]
43
+ #
44
+ # def initialize
45
+ # @instance_array = [8,9,10,11]
46
+ # end
47
+ # delegate :sum, to: :CONSTANT_ARRAY
48
+ # delegate :min, to: :@@class_array
49
+ # delegate :max, to: :@instance_array
50
+ # end
51
+ #
52
+ # Foo.new.sum # => 6
53
+ # Foo.new.min # => 4
54
+ # Foo.new.max # => 11
55
+ #
56
+ # It's also possible to delegate a method to the class by using +:class+:
57
+ #
58
+ # class Foo
59
+ # def self.hello
60
+ # "world"
61
+ # end
62
+ #
63
+ # delegate :hello, to: :class
64
+ # end
65
+ #
66
+ # Foo.new.hello # => "world"
67
+ #
68
+ # Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
69
+ # is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
70
+ # delegated to.
71
+ #
72
+ # Person = Struct.new(:name, :address)
73
+ #
74
+ # class Invoice < Struct.new(:client)
75
+ # delegate :name, :address, to: :client, prefix: true
76
+ # end
77
+ #
78
+ # john_doe = Person.new('John Doe', 'Vimmersvej 13')
79
+ # invoice = Invoice.new(john_doe)
80
+ # invoice.client_name # => "John Doe"
81
+ # invoice.client_address # => "Vimmersvej 13"
82
+ #
83
+ # It is also possible to supply a custom prefix.
84
+ #
85
+ # class Invoice < Struct.new(:client)
86
+ # delegate :name, :address, to: :client, prefix: :customer
87
+ # end
88
+ #
89
+ # invoice = Invoice.new(john_doe)
90
+ # invoice.customer_name # => 'John Doe'
91
+ # invoice.customer_address # => 'Vimmersvej 13'
92
+ #
93
+ # If the delegate object is +nil+ an exception is raised, and that happens
94
+ # no matter whether +nil+ responds to the delegated method. You can get a
95
+ # +nil+ instead with the +:allow_nil+ option.
96
+ #
97
+ # class Foo
98
+ # attr_accessor :bar
99
+ # def initialize(bar = nil)
100
+ # @bar = bar
101
+ # end
102
+ # delegate :zoo, to: :bar
103
+ # end
104
+ #
105
+ # Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
106
+ #
107
+ # class Foo
108
+ # attr_accessor :bar
109
+ # def initialize(bar = nil)
110
+ # @bar = bar
111
+ # end
112
+ # delegate :zoo, to: :bar, allow_nil: true
113
+ # end
114
+ #
115
+ # Foo.new.zoo # returns nil
116
+ def delegate(*methods)
117
+ options = methods.pop
118
+ unless options.is_a?(Hash) && to = options[:to]
119
+ raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
120
+ end
121
+
122
+ prefix, allow_nil = options.values_at(:prefix, :allow_nil)
123
+
124
+ if prefix == true && to =~ /^[^a-z_]/
125
+ raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
126
+ end
127
+
128
+ method_prefix = \
129
+ if prefix
130
+ "#{prefix == true ? to : prefix}_"
131
+ else
132
+ ''
133
+ end
134
+
135
+ file, line = caller.first.split(':', 2)
136
+ line = line.to_i
137
+
138
+ to = to.to_s
139
+ to = 'self.class' if to == 'class'
140
+
141
+ methods.each do |method|
142
+ # Attribute writer methods only accept one argument. Makes sure []=
143
+ # methods still accept two arguments.
144
+ definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block'
145
+
146
+ if allow_nil
147
+ module_eval(<<-EOS, file, line - 2)
148
+ def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
149
+ if #{to} || #{to}.respond_to?(:#{method}) # if client || client.respond_to?(:name)
150
+ #{to}.#{method}(#{definition}) # client.name(*args, &block)
151
+ end # end
152
+ end # end
153
+ EOS
154
+ else
155
+ exception = %(raise "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
156
+
157
+ module_eval(<<-EOS, file, line - 1)
158
+ def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
159
+ #{to}.#{method}(#{definition}) # client.name(*args, &block)
160
+ rescue NoMethodError # rescue NoMethodError
161
+ if #{to}.nil? # if client.nil?
162
+ #{exception} # # add helpful message to the exception
163
+ else # else
164
+ raise # raise
165
+ end # end
166
+ end # end
167
+ EOS
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,27 @@
1
+ module ModuleExt; end; module ModuleExt::Deprecation
2
+ require 'active_support/deprecation/method_wrappers'
3
+
4
+ refine Module do
5
+ # deprecate :foo
6
+ # deprecate bar: 'message'
7
+ # deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'
8
+ #
9
+ # You can also use custom deprecator instance:
10
+ #
11
+ # deprecate :foo, deprecator: MyLib::Deprecator.new
12
+ # deprecate :foo, bar: "warning!", deprecator: MyLib::Deprecator.new
13
+ #
14
+ # \Custom deprecators must respond to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt>
15
+ # method where you can implement your custom warning behavior.
16
+ #
17
+ # class MyLib::Deprecator
18
+ # def deprecation_warning(deprecated_method_name, message, caller_backtrace)
19
+ # message = "#{method_name} is deprecated and will be removed from MyLibrary | #{message}"
20
+ # Kernel.warn message
21
+ # end
22
+ # end
23
+ def deprecate(*method_names)
24
+ ActiveSupport::Deprecation.deprecate_methods(self, *method_names)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,80 @@
1
+ module ModuleExt; end; module ModuleExt::Introspection
2
+ require 'active_support/inflector'
3
+
4
+ refine Module do
5
+ # Returns the name of the module containing this one.
6
+ #
7
+ # M::N.parent_name # => "M"
8
+ def parent_name
9
+ if defined? @parent_name
10
+ @parent_name
11
+ else
12
+ @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
13
+ end
14
+ end
15
+
16
+ # Returns the module which contains this one according to its name.
17
+ #
18
+ # module M
19
+ # module N
20
+ # end
21
+ # end
22
+ # X = M::N
23
+ #
24
+ # M::N.parent # => M
25
+ # X.parent # => M
26
+ #
27
+ # The parent of top-level and anonymous modules is Object.
28
+ #
29
+ # M.parent # => Object
30
+ # Module.new.parent # => Object
31
+ def parent
32
+ parent_name ? ActiveSupport::Inflector.constantize(parent_name) : Object
33
+ end
34
+
35
+ # Returns all the parents of this module according to its name, ordered from
36
+ # nested outwards. The receiver is not contained within the result.
37
+ #
38
+ # module M
39
+ # module N
40
+ # end
41
+ # end
42
+ # X = M::N
43
+ #
44
+ # M.parents # => [Object]
45
+ # M::N.parents # => [M, Object]
46
+ # X.parents # => [M, Object]
47
+ def parents
48
+ parents = []
49
+ if parent_name
50
+ parts = parent_name.split('::')
51
+ until parts.empty?
52
+ parents << ActiveSupport::Inflector.constantize(parts * '::')
53
+ parts.pop
54
+ end
55
+ end
56
+ parents << Object unless parents.include? Object
57
+ parents
58
+ end
59
+
60
+ def local_constants #:nodoc:
61
+ constants(false)
62
+ end
63
+
64
+ # *DEPRECATED*: Use +local_constants+ instead.
65
+ #
66
+ # Returns the names of the constants defined locally as strings.
67
+ #
68
+ # module M
69
+ # X = 1
70
+ # end
71
+ # M.local_constant_names # => ["X"]
72
+ #
73
+ # This method is useful for forward compatibility, since Ruby 1.8 returns
74
+ # constant names as strings, whereas 1.9 returns them as symbols.
75
+ def local_constant_names
76
+ ActiveSupport::Deprecation.warn 'Module#local_constant_names is deprecated, use Module#local_constants instead', caller
77
+ local_constants.map { |c| c.to_s }
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,54 @@
1
+ module ModuleExt; end; module ModuleExt::QualifiedConst
2
+ require 'active_support/refinements/core_ext/string/inflections'
3
+
4
+ #--
5
+ # Allows code reuse in the methods below without polluting Module.
6
+ #++
7
+ module QualifiedConstUtils
8
+ def self.raise_if_absolute(path)
9
+ raise NameError.new("wrong constant name #$&") if path =~ /\A::[^:]+/
10
+ end
11
+
12
+ def self.names(path)
13
+ path.split('::')
14
+ end
15
+ end
16
+
17
+ ##
18
+ # Extends the API for constants to be able to deal with qualified names. Arguments
19
+ # are assumed to be relative to the receiver.
20
+ #
21
+ #--
22
+ # Qualified names are required to be relative because we are extending existing
23
+ # methods that expect constant names, ie, relative paths of length 1. For example,
24
+ # Object.const_get('::String') raises NameError and so does qualified_const_get.
25
+ #++
26
+ refine Module do
27
+ def qualified_const_defined?(path, search_parents=true)
28
+ QualifiedConstUtils.raise_if_absolute(path)
29
+
30
+ QualifiedConstUtils.names(path).inject(self) do |mod, name|
31
+ return unless mod.const_defined?(name, search_parents)
32
+ mod.const_get(name)
33
+ end
34
+ return true
35
+ end
36
+
37
+ def qualified_const_get(path)
38
+ QualifiedConstUtils.raise_if_absolute(path)
39
+
40
+ QualifiedConstUtils.names(path).inject(self) do |mod, name|
41
+ mod.const_get(name)
42
+ end
43
+ end
44
+
45
+ def qualified_const_set(path, value)
46
+ QualifiedConstUtils.raise_if_absolute(path)
47
+
48
+ const_name = path.demodulize
49
+ mod_name = path.deconstantize
50
+ mod = mod_name.empty? ? self : qualified_const_get(mod_name)
51
+ mod.const_set(const_name, value)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,10 @@
1
+ module ModuleExt; end; module ModuleExt::Reachable
2
+ require 'active_support/refinements/core_ext/module/anonymous'
3
+ require 'active_support/refinements/core_ext/string/inflections'
4
+
5
+ refine Module do
6
+ def reachable? #:nodoc:
7
+ !anonymous? && name.safe_constantize.equal?(self)
8
+ end
9
+ end
10
+ end